8

私は一日のようにこれに不満を感じています...助けてください。

JQueryを使用してDOM要素を追加/削除することで新しいアイテムを動的に追加できる請求書セクションがあります...これらの要素に正しく名前を付ける方法をすでに理解しているため、モデルに適切にマッピングされて送信されますアクションパラメータに。

したがって、コントローラーに「請求書」タイプのパラメーターを使用した「編集」というアクションがあるとします。

[HttpPost]
public virtual ActionResult Edit(Invoice invoice) {
    if (ModelState.IsValid) {
         //code discussed below
    }
    return RedirectToAction("Index");
}

請求書パラメータには、必要なすべてのデータが含まれています。私はこれに問題はありません。以下はオブジェクトモデルです。

public class Invoice
{
    [Key]
    public int ID { get; set; }
    public InvoiceType InvoiceType { get; set; }
    public string Description { get; set; }
    public int Amount { get; set; }
    public virtual ICollection<InvoiceItem> InvoiceItems { get; set; }
}

InvoiceItemsコレクションに注意してください。これには、動的に挿入された請求書アイテムのコレクションが含まれています。以下はInvoiceItemモデルです

[Table("InvoiceItems")]
public class InvoiceItem
{
    [Key]
    public int ID { get; set; }

    [ForeignKey("Invoice")]
    public int InvoiceID { get; set; }
    public Invoice Invoice { get; set; }

    public string Description { get; set; }
    public int Amount { get; set; }
}

そして、それは私が立ち往生しているところです。

InvoiceコレクションInvoiceItemsのアイテムをデータベースに挿入/更新できません。私はたくさんグーグルしていて、これらの解決策を見つけました-残念ながら、これらのどれもうまくいきません。

解決策#1 -SetValuesを使用した奇妙なコード:

Invoice origInvoice = db.Invoices.Single(x => x.ID == invoice.ID);
var entry = db.Entry(origInvoice);
entry.OriginalValues.SetValues(invoice);
entry.CurrentValues.SetValues(invoice);
db.SaveChanges();

解決策#2-新しい更新メソッドをDbContextに追加します。

public void Update<T>(T entity) where T : class
{
   this.Set<T>().Attach(entity);
   base.ObjectContext.ObjectStateManager.ChangeObjectState(entity,System.Data.EntityState.Modified);
 }

解決策#3 - http://blogs.msdn.com/b/adonet/archive/2011/01/29/using-dbcontext-in-ef-feature-ctp5-partに従って、既存の変更されたエンティティをコンテキストにアタッチする-4-add-attach-and-entity-states.aspx

db.Entry(invoice).State = EntityState.Modified;
db.SaveChanges();

ソリューション#1の仕組み:新しく追加されたInvoiceItemsを除くすべてのプロパティを更新します。SetValues()はICollectionプロパティを無視します。これは、db.SaveChanges();の直前にこの行を追加した場合に機能します。

origEntry.Entity.InvoiceItems = invoice.InvoiceItems;

...しかし、これが正しいアプローチだとはまったく思いません。

ソリューション#2の仕組み: DbContextクラスにObjectContextプロパティがないため、まったく機能しません。

ソリューション#3の仕組み:このソリューションは請求書を更新しますが、それ以外の場合はInvoiceItemsを無視します。


追加情報:以下は、InvoiceItemプロパティにマップされるアイテム要素を生成するために使用されるJavaScriptの一部です。

    window.InvoiceItemIndex++;

    var str = $.tmpl("itemRowTmpl", {
        itemIndexes: '<input type="hidden" name="Invoice.InvoiceItems.Index" value="' + window.InvoiceItemIndex + '"/> \
                      <input type="hidden" name="Invoice.InvoiceItems[' + window.InvoiceItemIndex + '].ID" value="0"/>\
                      <input type="hidden" name="Invoice.InvoiceItems[' + window.InvoiceItemIndex + '].InvoiceID" value="@Model.Invoice.ID"/>',
        itemDescription: '<textarea cols="150" name="Invoice.InvoiceItems[' + window.InvoiceItemIndex + '].Description" rows="2"></textarea>',
        itemAmount: '<input type="text" class="InvoiceItemAmount" style="text-align:right;" name="Invoice.InvoiceItems[' + window.InvoiceItemIndex + '].Amount" />',
    });

最後の質問:私は何が間違っているのですか?別のモデルに関連するアイテムの新しいコレクションがデータベースに自動的に挿入されることの何が問題になっていますか?親モデルが正常に更新されたときに、なぜ無視されるのですか?

編集1:修正

4

1 に答える 1

6

DbEntityEntry.CurrentValues.SetValuesスカラープロパティと複雑なプロパティのみを更新します。ナビゲーションプロパティは関係ありません。InvoiceItemsこれが、コレクションの変更がデータベースに書き込まれない理由です。同じ問題は、の状態をに設定するInvoiceことModifiedです。これは、スカラーおよび複雑なプロパティを変更済みとしてマークするだけで、ナビゲーションプロパティはマークしません。

残念ながら、EFは、エンティティがコンテキストから切り離されている間に変更が行われた場合に、ナビゲーションコレクション内のどのアイテムがデータベースの元の状態と比較して追加、削除、または変更されたかを分析する簡単な方法を提供していません。 (例のWebページ上)。

これは、データベース内の元の状態と新しく変更された状態を自分で比較する必要があることを意味します。

これを行う方法のコード例は、たとえばここの回答にあります。1つ以上の外部キープロパティがnull許容ではないため、関係を変更できませんでした。例は状況に非常によく適合しParentItemます。InvoiceChildItemsInvoiceItems

追加情報については、数日前のこの質問を参照することもできます:WCF、Entity Framework 4.1、およびエンティティの状態デタッチされたオブジェクトグラフの更新のサポートの欠如と同じ問題に関係する他の多くの質問が実際にあります(これは非常に一般的なシナリオです)は、EntityFrameworkのより不快な制限の1つです。

(注:MVCコントローラーにはUpdateModelメソッドがあります。このメソッドが完全なオブジェクトグラフを更新できるかどうかはわかりません(コレクション内のアイテムを追加、削除、変更します)。個人的には使用していません。それを使用する場合は、DBモデルを操作するためではなく、ViewModelの更新のためだけに使用します。)

于 2011-08-13T19:24:30.963 に答える