以下にリストされているプロファイルモデルがあります。このモデルは、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から取得しました。
私を正しい方向に向けるための助けは大歓迎です。