2009-08-25 55 views
4

當我嘗試使用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)); } 
    } 
} 

回答

3

是否因爲您正在調用.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

0

根據我的經驗,這類問題通常來自映射配置中的錯誤。

尋找答案的一些建議:

  • 使用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

0

我看,你是不是使用了「自動綁定」(或者無論你怎麼稱呼它,在那裏你接受實體想要綁定的動作方法參數),但代替(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

1

我就遇到了這個問題,因爲我已經在我的.dbml *文件Ling2SQL設置Auto Generated Value選項true;我將其更改爲false,錯誤消失。這是一個簡單的錯誤,但它讓我永遠找到,因爲我沒有故意將值設置爲true