LINQ to SQL INSERT失败

问题描述:

当我尝试使用LINQ to SQL插入新记录 时,我遇到了一个非常令人沮丧的问题。如果我单步执行此代码,有时会插入新记录 ,但大多数情况下不会。当它失败时,我看到以下错误。LINQ to SQL INSERT失败

无法插入NULL值插入 列 '名称',表 'EquipmentManufacturer';列确实是 不允许有空值。 INSERT失败。 声明已被终止。

这个错误是抱怨'姓名'字段为空,但不应该是这种情况。当我调试并逐步完成这个集合时[[Name]]具有我在表单中输入的值。

这是表格创建语句。

CREATE TABLE [EquipmentManufacturer] (
    [EquipmentManufacturerID] [int] IDENTITY(1,1) NOT NULL, 
    [Name] [nvarchar](50) NOT NULL, 

CONSTRAINT [PK_EquipmentManufacturer] PRIMARY KEY CLUSTERED 
(
    [EquipmentManufacturerID] ASC 
) ON [PRIMARY] 
) ON [PRIMARY] 

这里是ASP.NET MVC控制器和创建操作,我试图添加一条新记录。

public partial class EquipmentManufacturerController : Controller 
{ 
    private IRepository<EquipmentManufacturer> reposManu; 

    // POST: /EquipmentManufacturer/Create 
    [AcceptVerbs(HttpVerbs.Post)] 
    public virtual ActionResult Create(FormCollection collection) 
    { 
    EquipmentManufacturer entity = reposManu.New(); 
    try 
    { 
     //HACK: Something screwy is going on here the entity oject doesn't always get updated correctly 
     //UpdateModel(entity); 

     entity.Name = collection["Name"]; 
     reposManu.Insert(entity); 
     reposManu.SubmitChanges(); 

     return RedirectToAction("Details", new { id = entity.EquipmentManufacturerID }); 
    } 
    catch (RulesException ex) 
    { 
     ex.AddModelStateErrors(ModelState, "EquipmentManufacturer"); 
     return ModelState.IsValid ? RedirectToAction("Create") 
     : (ActionResult)View(); 
    } 
    } 
} 

这里是Create.aspx视图。

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server"> 

    <h2>Create</h2> 

    <%= Html.ValidationSummary("Create was unsuccessful. Please correct the errors and try again.") %> 

    <% using (Html.BeginForm()) {%> 

     <fieldset> 
      <legend>Fields</legend> 
      <p> 
       <label for="Name">Name:</label> 
       <%= Html.TextBox("Name") %> 
       <%= Html.ValidationMessage("Name") %> 
      </p> 
      <p> 
       <input type="submit" value="Create" /> 
      </p> 
     </fieldset> 

    <% } %> 
    <%= Html.ClientSideValidation<EquipmentManufacturer>() %> 

    <div> 
     <%=Html.ActionLink("Back to List", "Index") %> 
    </div> 

</asp:Content> 

这是我正在使用的Repository实现。

public class Repository<T> : IRepository<T> where T : class 
{ 
    public IDataContext DC { get; set; } 

    public Repository(IDataContext dataContext) 
    { 
     DC = dataContext; 
    } 

    /// <summary> 
    /// Return all instances of type T. 
    /// </summary> 
    /// <returns></returns> 
    public IEnumerable<T> All() 
    { 
     return GetTable; 
    } 

    /// <summary> 
    /// Return all instances of type T that match the expression exp. 
    /// </summary> 
    /// <param name="exp"></param> 
    /// <returns></returns> 
    public IQueryable<T> Find(Expression<Func<T, bool>> exp) 
    { 
     return GetTable.Where<T>(exp); 
    } 

    /// <summary>See IRepository</summary> 
    /// <param name="exp"></param> 
    /// <returns></returns> 
    public T Single(Expression<Func<T, bool>> exp) 
    { 
     return GetTable.SingleOrDefault(exp); 
    } 

    /// <summary>See IRepository</summary> 
    /// <param name="exp"></param> 
    /// <returns></returns> 
    public T First(Expression<Func<T, bool>> exp) 
    { 
     return GetTable.First(exp); 
    } 

    /// <summary>See IRepository</summary> 
    /// <param name="entity"></param> 
    public virtual void Delete(T entity) 
    { 
     DC.Context.GetTable<T>().DeleteOnSubmit(entity); 
    } 

    /// <summary> 
    /// Create a new instance of type T. 
    /// </summary> 
    /// <returns></returns> 
    public virtual T New() 
    { 
     T entity = Activator.CreateInstance<T>(); 
     GetTable.InsertOnSubmit(entity); 
     return entity; 
    } 

    /// <summary> 
    /// Adds an insance T. 
    /// </summary> 
    /// <returns></returns> 
    public virtual void Insert(T entity) 
    { 
     GetTable.InsertOnSubmit(entity); 
    } 

    /// <summary> 
    /// Update entity. 
    /// </summary> 
    /// <returns></returns> 
    public virtual void Update(T entity) 
    { 
     DC.Context.Refresh(System.Data.Linq.RefreshMode.KeepCurrentValues, entity); 
    } 

    /// <summary>See IRepository</summary> 
    public void SubmitChanges() 
    { 
     DC.SubmitChanges(); 
    } 

    private string PrimaryKeyName 
    { 
     get { return TableMetadata.RowType.IdentityMembers[0].Name; } 
    } 

    private System.Data.Linq.Table<T> GetTable 
    { 
     get { return DC.Context.GetTable<T>(); } 
    } 

    private System.Data.Linq.Mapping.MetaTable TableMetadata 
    { 
     get { return DC.Context.Mapping.GetTable(typeof(T)); } 
    } 

    private System.Data.Linq.Mapping.MetaType ClassMetadata 
    { 
     get { return DC.Context.Mapping.GetMetaType(typeof(T)); } 
    } 
} 

是否因为您正在调用.InsertOnSubmit(实体)两次?

你曾经在新的()

public virtual T New() 
{ 
    T entity = Activator.CreateInstance<T>(); 
    GetTable.InsertOnSubmit(entity); 
    return entity; 
} 

在.insert()这样

public virtual void Insert(T entity) 
{ 
    GetTable.InsertOnSubmit(entity); 
} 

我个人取下新的GetTable.InsertOnSubmit(实体)()再次调用它,然后方法。

原因是我认为对于存储库的用户来说,明确地插入实体会更好,而不是每次创建新实体时都会自动设置插入。

HTHS,
查尔斯

+0

这似乎解决了我的问题,但我不太确定为什么。如果我从Repository New方法注释掉GetTable.InsertOnSubmit(实体),它会起作用。如果我在Repository New方法中留下InsertOnSubmit调用,并在控制器中注释掉reposManu.Insert(entity)调用,它将失败。 – MHinton 2009-08-26 13:12:57

+0

根据你刚才所说的判断,当你调用.InsertOnSubmit(entity)时,它需要一个对象的副本来保存它。因此,当你打电话给.InsertOnSubmit打上新的EquipmentManufacturer品牌时,它会尝试插入一个不包含任何值的副本,因此它会因数据库限制而失败。 – Charlino 2009-08-26 19:49:46

+0

谢谢,这实际上是有道理的。 – MHinton 2009-08-27 00:48:57

根据我的经验,这类问题通常来自映射配置中的错误。

寻找答案的一些建议:

  • 使用SQL事件探查器跟踪的INSERT语句,这可能会给你更多的线索。

  • 再次检查EquipmentManufacturer类的映射,名称可能未正确映射。将这些信息包含在您的问题中,因为它可以更好地了解问题。

+0

我已经使用了SQL Profiler,并且看到传入的Name参数为null。我不知道发生了什么,因为在这一行reposManu.Insert(entity)entity.Name不是null。 – MHinton 2009-08-26 02:31:38

+0

通过LINQ to SQL在检索要插入的值时执行的跟踪 - 显然存在名称列的映射,因为它在SQL中,但您是否已检查映射条目(属性或XML)是否实际指向正确的属性/字段在你的实体类? – Sam 2009-08-26 04:58:05

我看,你是不是使用了“自动绑定”(或者无论你怎么称呼它,在那里你接受实体想要绑定的动作方法参数),但代替(A)newing对象和(B)手动设置formCollection的“Name”属性。也许我没有看到“EquipmentManufacturerID”被绑定在哪里?

此EquipmentManufacturerID属性是否为NULL失败?

+0

在Name属性上没有它。我尝试过使用公共虚拟ActionResult创建([Bind()] EquipmentManufacturer)方法签名,我仍然有同样的问题。 – MHinton 2009-08-26 02:27:49

+0

您是否尝试过记录LTS生成的底层SQL?如果你能看到它发送的服务器是什么,它可能会帮助你进一步调试......? – Funka 2009-08-26 04:01:25

我就遇到了这个问题,因为我已经在我的.dbml *文件Ling2SQL设置Auto Generated Value选项true;我将其更改为false,错误消失。这是一个简单的错误,但它让我永远找到,因为我没有故意将值设置为true