1

以下にリストされているプロファイルモデルがあります。このモデルは、ajax 呼び出しを介してクライアントに送信され、更新され、別の ajax 呼び出しを介してサーバーに送り返されます。

クライアントが変更を行う場合、クライアントは、使用しているモデルの ObjectState を設定する責任があります。たとえば、Name プロパティを変更する場合、Name プロパティを新しい値に設定し、ObjectState プロパティを 2 (Modified) に設定し、新しい Address を Addresses に追加するには、新しい Address の ObjectState を 1 に設定します。 (追加した)。これはすべてうまく機能し、ApiController は新しい Profile オブジェクトを適切に受け取ります。

public enum ObjectState
{
    Unchanged = 0,
    Added = 1,
    Modified = 2,
    Deleted = 3
}

public interface IObjectState
{
    ObjectState ObjectState { get; set; }
}

static class EntityStateHelper
{
    public static EntityState ConvertState(ObjectState objectState)
    {
        switch (objectState)
        {
            case ObjectState.Added:
                return EntityState.Added;
            case ObjectState.Deleted:
                return EntityState.Deleted;
            case ObjectState.Modified:
                return EntityState.Modified;
            default:
                return EntityState.Unchanged;
        }
    }
}

// Models
public class Profile : IObjectState
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime? BirthDay { get; set; }

    // Navigation Properties
    public ICollection<Address> Addresses { get; set; }

    public ObjectState ObjectState { get; set; }
}

public class Address : IObjectState
{
    public int Id { get; set; }
    public string Street1 { get; set; }
    public string Street2 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip { get; set; }
    public ObjectState ObjectState { get; set; }
}

私の ProfileRepository 内では、実際に Insert と Update を分離しました。Profile オブジェクトの場合、クライアントにはプロファイルを削除するためのサービス呼び出しがないため、プロファイルに対して実際にできることはプロファイルを変更することだけです。私の Update メソッドでは、同じキーを持つオブジェクトが ObjectStateManager に既に存在することを示す例外をスローするように_context.Entry<T>(entity)、並置されたままにすることを選択しました。ObjectStateManager は、同じキーを持つ複数のオブジェクトを追跡できません_context.Entry<T>(entity).State = EntityState.Modified

public void Update(T entity)
{
    _context.Entry<T>(entity);
    _context.ApplyStateChanges();
}

最初に、実際には Update メソッドに ApplyStateChanges はありませんが、このサンプルでは何が起こっているかを示します。以下は ApplyStateChanges メソッドのコードです。

public static class DbContextEntensions
{
    public static void ApplyStateChanges(this DbContext context)
    {
        foreach (var trackableEntry in context.ChangeTracker.Entries<IObjectState>())
        {
            IObjectState state = trackableEntry.Entity;
            trackableEntry.State = EntityStateHelper.ConvertState(state.ObjectState);
        }
    }
} 

ここに問題があります。クライアントのプロファイルで、Name プロパティが John で、Addresses プロパティに 1 つのアドレスが含まれているとします。クライアントが Name を Steve に変更し、1 つの Address を変更した場合、ApplyStateChanges が適切な EntityState でマークされたそれぞれの DbEntityEntries と呼ばれる場合、すべてが正当な原因です。この問題は、クライアントが Addresses コレクションに State 1 (追加済み) の新しいアドレスを追加したときに発生します。ApplyStateChanges が呼び出されると、その呼び出しはcontext.ChangeTracker.Entries<IObjectState>()、ChangeTracker によって変更されたエントリとして新しく追加されたアドレスを返しません。

_context.Entry<T>(entity)コードがそうあるべきだと確信しています_context.Entry<T>(entity).State = EntityState.Modifiedが、何を試してもこの例外を回避できないようです。

4.4 の EntityFramework バージョンを意味する .NET 4.0 で EntityFramework 5.0 を使用しています。私は何が欠けていますか?私は、この件に関して見つけることができるすべての記事であると感じているものを読みましたが、これはうまくいくようです. この State change tracking コードは、Julie Lerman の PluralSight ビデオEntity Framework in the Enterpriseから取得しました。

私を正しい方向に向けるための助けは大歓迎です。

4

2 に答える 2

0

Update メソッドで .Add(entity) を使用してエンティティを追加することをお勧めします。これにより、新しいアドレスが追加済みとしてマークされ、そのナビゲーション プロパティが修正されます。その後、ApplyStateChanges を呼び出すと、状態が修正されます。

于 2013-10-29T17:18:37.567 に答える
0

この投稿は古いですが、他の人に役立つかもしれません:

問題は Update メソッドにあります。切断モードで作業していると思います。以下の方法:

_context.Entry<T>(entity);

コンテキストからエンティティを取得します。
その中にない場合は、それ (およびそのナビゲーション プロパティを Address として) を "Detached" EntityState と共に追加します。

代わりに「.Add(entity)」または「.Attach(entity)」を使用する必要があります。唯一の違いは状態です:

  • .Add は、顧客とその住所を EntityState : "Added" で追加します。

  • .Attach は、顧客とその住所を EntityState : "Unchanged" で追加します。

以下の行の後で状態を変更すると(再び!)、両方ともコードで機能します。

_context.ApplyStateChanges();

これは、追跡されている限り (デタッチ状態でない限り)、以前に適用した状態を気にしないことを意味します。

コード _context.Entry(entity) が _context.Entry(entity).State = EntityState.Modified であることは確かですが、何を試してもこの例外を回避できないようです。

後で ApplyStateChanges() を実行しないと、エンティティの更新とそのグラフ全体がダーティとしてマークされ、予期しない結果が生じます (グラフ要素を追加するのと同じように。説明全体でこの回答を確認してください)。

同じキーを持つオブジェクトが ObjectStateManager に既に存在します。ObjectStateManager は、同じキーを持つ複数のオブジェクトを追跡できません。

これは、データベース/テストに同じオブジェクト (または、より確実にそのナビゲーション プロパティの 1 つ) が既にあることを意味します。これは「実際の」問題とは関係なく、副作用である可能性が高くなります。データベースの Seed メソッドをチェックインします。重複したナビゲーション エンティティが必要です。

于 2015-12-08T10:10:49.667 に答える