少し前に、特定のエンティティに対して挿入または更新を行うかどうかを判断できるメソッドを実装したかったので、"Insert" メソッドと "Update" メソッドを公開する必要はありませんでしたが、単純な "InsertOrUpdate "。
エンティティが新しいかどうかを確認するコードの部分は次のとおりです。
public virtual T GetEntityByPrimaryKey<T>(T entity) where T : class
{
var entityType = entity.GetType();
var objectSet = ((IObjectContextAdapter)this.DatabaseContext).ObjectContext.CreateObjectSet<T>();
var keyNames = objectSet.EntitySet.ElementType.KeyMembers.Select(edmMember => edmMember.Name);
var keyValues = keyNames.Select(name => entityType.GetProperty(name).GetValue(entity, null)).ToArray();
return this.DatabaseContext.Set<T>().Find(keyValues);
}
InsertOrUpdate メソッドは次のとおりです。
public virtual T InsertOrUpdate<T>(T entity) where T : class
{
var databaseEntity = this.GetEntityByPrimaryKey(entity);
if (databaseEntity == null)
{
var entry = this.DatabaseContext.Entry(entity);
entry.State = EntityState.Added;
databaseEntity = entry.Entity;
}
else
{
this.DatabaseContext.Entry(databaseEntity).CurrentValues.SetValues(entity);
}
return databaseEntity;
}
現在、このアプローチは、オブジェクトの「主キー」がコードによって決定されている限り、驚異的に機能します。有効な例は、GUID、HI-LO アルゴリズム、自然キーなどです。
ただし、これは「データベースで生成された ID」シナリオではひどく壊れており、その理由は非常に単純です。コード内の「ID」は、挿入するすべてのオブジェクトに対して 0 になるため、メソッドはそれらを考慮します。同じ。10 個のオブジェクトを追加すると、最初のオブジェクトは「新規」になりますが、次の 9 個は「既存のもの」になります。これは、EF の "Find" メソッドが objectcontext からデータを読み取り、それが存在しない場合にのみデータベースにアクセスしてクエリを実行するためです。
最初のオブジェクトの後、ID 0 の特定のタイプのエンティティが追跡されます。連続して呼び出すと「更新」が行われますが、これは間違っています。
データベースで生成された ID は悪であり、どの ORM にもまったく適していないことはわかっていますが、私はそれらに固執しており、このメソッドを修正するか、完全に削除して別の「挿入」メソッドと「更新」メソッドにフォールバックする必要があります。何をすべきかを決定するタスクを発信者に委任します。高度に分離されたソリューションがあるため、これを行うことは避けたいと思います。
GetEntityByPrimaryKey メソッドを修正する方法を見つけて助けてくれる人がいれば、それは素晴らしいことです。
ありがとう。