5

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

値 NULL を列 'Name'、テーブル 'EquipmentManufacturer' に挿入できません。列はヌルを許可しません。INSERT は失敗します。ステートメントは終了されました。

このエラーは、「名前」フィールドが null であることを訴えていますが、そうではありません。このコレクションをデバッグしてステップ実行すると、フォームに入力した値が ["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>

これが私が使用しているリポジトリの実装です。

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)); }
  }
}
4

4 に答える 4

3

.InsertOnSubmit(entity) を 2 回呼び出しているためですか?

New() で一度呼び出します

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(entity) を New() メソッドから削除します。

その理由は、リポジトリのユーザーが新しいエンティティを作成するたびにエンティティを自動的に挿入するよりも、エンティティを具体的に挿入する方が良いと思うからです。

HTH、
チャールズ

于 2009-08-26T04:45:07.893 に答える
1

Auto Generated Value*.dbml Ling2SQL ファイルのオプションをtrue;に設定していたため、この問題に遭遇しました。に変更したところfalse、エラーはなくなりました。単純な間違いですが、意図的に値を に設定しなかったため、見つけるのに永遠にかかりましたtrue

于 2011-12-26T08:38:05.273 に答える
0

「自動バインド」(またはアクションメソッドパラメーターとしてバインドするエンティティを受け入れる場合)を使用していないことがわかりますが、代わりに(A)オブジェクトを新規作成し、(B)その「 FormCollection の Name" プロパティを手動で削除します。おそらく、「EquipmentManufacturerID」がバインドされている場所がわかりませんか?

この EquipmentManufacturerID プロパティの NULL エラーですか?

于 2009-08-26T00:59:47.117 に答える
0

私の経験では、この種の問題は通常、マッピング構成のエラーが原因です。

答えを見つけるためのいくつかの提案:

  • SQL プロファイラーを使用して INSERT ステートメントをトレースすると、より多くの手がかりが得られる場合があります。

  • EquipmentManufacturer クラスのマッピングを再確認してください。名前が正しくマッピングされていない可能性があります。問題のより良い全体像を提供するため、その情報を質問に含めてください。

于 2009-08-26T00:41:09.023 に答える