2009-08-25 18 views
4

LINQ to SQLを使用して新しいレコード を挿入しようとすると、非常に不満な問題が発生します。このコードをステップ実行すると、新しいレコード が挿入されることがありますが、ほとんどの場合は挿入されません。失敗すると、次のエラーが表示されます。LINQ to SQL INSERTに失敗する

コラム '名前'、表 にNULL値を挿入することはできません 'EquipmentManufacturer';列は はnullを許可しません。 INSERTは失敗します。 ステートメントが終了しました。

このエラーは、「名前」フィールドがnullであると不平を言っていますが、そうではありません。このコレクション["Name"]をデバッグしてステップ実行すると、フォームに入力した値があります。

ここにtable create文があります。

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> 

私が使用しているリポジトリの実装は次のとおりです。

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(エンティティ)を2回呼び出すためですか?

あなたが個人的に私は新しい(からGetTable.InsertOnSubmit(エンティティ)を削除します

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

)(.Insertで

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

そして再び)(新に一度それを呼び出します)方法。

なぜなら、リポジトリのユーザーは、新しいものを作成するたびに挿入するために自動的に設定されるのではなく、具体的にエンティティを挿入するほうがよいと思うからです。 ;私はtrueに私* .dbml Ling2SQLファイルにAuto Generated Valueオプションを設定していたので、私はこの問題に遭遇した

HTHS、
チャールズ

+0

これは私の問題を解決するようですが、私はなぜそれほど確かではありません。私がリポジトリのNewメソッドからGetTable.InsertOnSubmit(エンティティ)をコメントアウトすると、それは機能します。リポジトリの新規メソッドでInsertOnSubmitコールを残し、コントローラでreposManu.Insert(エンティティ)コールをコメントアウトすると失敗します。 – MHinton

+0

ちょうど言ったことで判断すると、.InsertOnSubmit(エンティティ)を呼び出すときにオブジェクトを保存するためにオブジェクトのコピーが必要になります。したがって、新しいEquipmentManufacturerというブランドのブランドでInSertOnSubmitを呼び出すと、値を含まないコピーを挿入しようとします。そのため、データベースの制約に失敗します。 – Charlino

+0

ありがとうございました。 – MHinton

0

私の経験では、この種の問題は一般的にマッピング設定のエラーに起因します。

答え見つけるためのヒント:あなたはより多くの手がかりを与えるかもしれないINSERT文を、トレースする

  • 使用SQLプロファイラを。

  • EquipmentManufacturerクラスのマッピングを再度確認すると、Nameが正しくマップされないことがあります。あなたの質問にその情報を含めると、問題のより良いイメージが得られます。

+0

SQLプロファイラを使用しましたが、渡されたNameパラメータがnullであることがわかりました。私はこの行でreposManu.Insert(entity)entity.Nameがnullではないので、何が起こっているのか分かりません。 – MHinton

+0

挿入する値を取得するときにLINQ to SQLが実行する処理をトレースします.SQLにあるようにName列のマッピングは明らかですが、マッピングエントリ(属性またはXML)が実際にエンティティクラスの正しいプロパティ/フィールド? – Sam

0

私はあなたが「自動バインド」を使用していないことを確認(またはあなたがそれを呼び出す何でも、あなたはアクションメソッドのパラメータとしてバインドするエンティティを受け入れる)代わりにしている(A)NEWINGオブジェクト(B) "Name"プロパティをformCollectionから手動で設定します。おそらく私は "EquipmentManufacturerID"がどこに縛られているのか分からないでしょうか?

このEquipmentManufacturerIDプロパティでNULLが失敗しましたか?

+0

名前プロパティにその項目がありません。私は、public virtual ActionResult Create([Bind()] EquipmentManufacturerのようなメソッドシグネチャを使用しようとしましたが、私はまだ同じ問題を抱えています。 – MHinton

+0

LTSが生成している基礎となるSQLをログに記録しようとしましたか?サーバーの送信内容を確認できれば、これをさらにデバッグするのに役立つでしょう...? – Funka

1

私はそれをfalseに変更し、エラーは消え去った。その単純な間違いが、私は意図的に値をtrueに設定していないので、私は永遠に見つけました。