6

CustomerASP.NET Web API と Entity Framework 5 コード ファーストを使用してデータベース内の を更新しようとしていますが、うまくいきません。私のエンティティは次のようになります。

public class CustomerModel
{
    public int Id { get; set; }
    public string Name { get; set; }

    // More fields

    public ICollection<CustomerTypeModel> CustomerTypes { get; set; }
}

public class CustomerTypeModel
{
    public int Id { get; set; }
    public string Type { get; set; }

    [JsonIgnore]
    public ICollection<CustomerModel> Customers { get; set; }
}

それほど特別なことは何もありません。ユーザーが名前を入力し、1 つ以上の顧客タイプをチェックすることで顧客を追加できる Web インターフェイスを作成しました。送信ボタンを押すと、データが Web API メソッドに送信されます。

public void Put([FromBody]CustomerModel customer)
{
    using (var context = new MyContext())
    {
        context.Customers.Attach(customer);
        context.Entry(customer).State = EntityState.Modified;
        context.SaveChanges();
    }
}

これにより顧客フィールドが更新されますが、関連する顧客タイプは無視されます。着信オブジェクトには、関連付ける必要がある次customerのリストが含まれています。CustomerTypes

[0] => { Id: 1, Type: "Finance", Customers: Null },
[1] => { Id: 2, Type: "Insurance", Customers: Null }
[2] => { Id: 3, Type: "Electronics", Customers: Null }

ただし、このリストを見て関連するエンティティを追加/削除する代わりに、EF はそれを無視します。新しい関連付けは無視され、既存の関連付けは削除されてもそのまま残ります。

顧客をデータベースに挿入するときにも同様の問題がありました。これは、これらのエンティティの状態を に調整したときに修正されましたEntityState.Unchanged。当然のことながら、更新シナリオでこの同じ魔法の修正を適用しようとしました。

public void Put([FromBody]CustomerModel customer)
{
    using (var context = new MyContext())
    {
        foreach (var customertype in customer.CustomerTypes)
        {
            context.Entry(customertype).State = EntityState.Unchanged;
        }

        context.Customers.Attach(customer);
        context.Entry(customer).State = EntityState.Modified;
        context.SaveChanges();
    }
}

しかし、EF は同じ動作を示し続けます。

これを修正する方法についてのアイデアはありますか? それとも、リストを手動でクリアしてからCustomerTypes手動で追加するだけですか?

前もって感謝します。

JP

4

2 に答える 2

10

これは、エンティティの状態を設定するだけでは実際には解決できません。最初に、現在のすべてのタイプを含めてデータベースから顧客をロードし、次に、投稿された顧客の更新されたタイプ コレクションに従って、ロードされた顧客からタイプを削除するか、タイプを追加する必要があります。変更追跡は、結合テーブルからエントリを削除するか、新しいエントリを挿入するために残りを行います。

public void Put([FromBody]CustomerModel customer)
{
    using (var context = new MyContext())
    {
        var customerInDb = context.Customers.Include(c => c.CustomerTypes)
            .Single(c => c.Id == customer.Id);

        // Updates the Name property
        context.Entry(customerInDb).CurrentValues.SetValues(customer);

        // Remove types
        foreach (var typeInDb in customerInDb.CustomerTypes.ToList())
            if (!customer.CustomerTypes.Any(t => t.Id == typeInDb.Id))
                customerInDb.CustomerTypes.Remove(typeInDb);

        // Add new types
        foreach (var type in customer.CustomerTypes)
            if (!customerInDb.CustomerTypes.Any(t => t.Id == type.Id))
            {
                context.CustomerTypes.Attach(type);
                customerInDb.CustomerTypes.Add(type);
            }

        context.SaveChanges();
    }
}
于 2013-05-16T18:03:09.253 に答える
0

よりクリーンなソリューションは次のとおりです。

public void Put([FromBody]CustomerModel customer)
{
    using (var context = new MyContext())
    {
        var customerInDb = context.Customers.Include(c => c.CustomerTypes)
            .Single(c => c.Id == customer.Id);

        // Updates the Name property
        context.Entry(customerInDb).CurrentValues.SetValues(customer);

        // Remove types
        customer.CustomerTypes.Clear();

        // Add new types
        foreach (var type in customer.CustomerTypes) 
        {
            context.CustomerTypes.Attach(type);
            customerInDb.CustomerTypes.Add(type);
        }

        context.SaveChanges();
    }
}
于 2014-03-06T16:40:28.257 に答える