Linq to Entities:エンティティ、EntityKeys、Attached、およびNew Objectsの混合グラフ
-
06-07-2019 - |
質問
データモデルでは、オブジェクト/テーブル/データの間にかなり一般的な区分があります:
- "トランザクション"システムによって行われている作業を表すエンティティ。これらのエンティティはシステムによって作成され、特定のコンテキストでのみ重要です。それらは定期的にその場で作成されます。 (脇:このタイプのエンティティには適切な名前がありますか?)
- "データ辞書"トランザクションエンティティの一般的なプロパティを表すエンティティ。これらは不規則に(主にプロジェクトの開始時に)定義され、はるかに静的なライフサイクルを持っています。通常、私が作成します。
したがって、たとえば、User(トランザクション)エンティティとUserType(データディクショナリ)エンティティがあります。
データディクショナリエンティティのインスタンスへの参照をコードに(ハード)コード化したい。これにより、ビジネスロジックをわかりやすい言語でコーディングすることができます。 (たとえば、「平野」のUserTypeと「Admin」のUserTypeがあり、「ユーザーのUserTypeがAdminに等しい場合にのみアクセスを許可する」というルールがあります。)
LINQ-to-Entitiesをデータアクセステクノロジー/ ORMとして使用しています。データディクショナリ参照を実装するために、EntityKeysを格納しています。私の理解では、それらはオブジェクトコンテキストから切り離されているため、この目的に適しています。 (エンティティの状態が含まれていないため、その状態が古くなることを心配する必要もありません。)
ただし、DD-EntityKey-referenceを使用して新しいトランザクションエンティティを追加しようとすると、問題が発生します。私の例を続けて、私はこれをしています:
UserEntities userEntities = new UserEntitites()
User user = new User()
user.UserType = new UserType()
user.UserType.EntityKey = adminEntityKey
userEntities.AddToUser(user)
...これにより、次のエラーが表示されます:
System.InvalidOperationException:オブジェクトは既にEntityKeyを持っているため、ObjectStateManagerに追加できません。 ObjectContext.Attachを使用して、既存のキーを持つオブジェクトをアタッチします。
AddToUserの代わりにuserEntities.Attach(user)を呼び出そうとすると、次のようになります。
System.InvalidOperationException:EntityKey値がnullのオブジェクトは、オブジェクトコンテキストにアタッチできません。
これらのエラーは、私がやっている新しいエンティティと既存のエンティティが混在していることを考えると、理にかなっています。私が確信していないのは、この問題を回避する方法です。 DDエンティティへの参照をデタッチし、DDエンティティの状態全体を読み込むことなく、それらを新しい添付オブジェクトに割り当てる方法はありますか?
解決
これらの例外が発生する理由を説明しよう:
System.InvalidOperationException:オブジェクトは既にEntityKeyを持っているため、ObjectStateManagerに追加できません。 ObjectContext.Attachを使用して、既存のキーを持つオブジェクトをアタッチします。
新しいUserおよびUserTypeエンティティが作成されます。 UserTypeのEntityKeyは設定されていますが、userEntities.Add()に渡すと、EFはそれらのステータスをADDEDに設定しようとします。 UserTypeにはEntityKeyがあるため、EFは何かが間違っていることを認識し、例外をスローします。
System.InvalidOperationException:EntityKey値がnullのオブジェクトは、オブジェクトコンテキストにアタッチできません。
この例外では、UserTypeはすべて問題ありませんが、ユーザーエンティティ-EntityKeyがないため、添付できないため、例外がスローされます。
これは私がこの問題を解決する方法です(あなたが言うように、データ辞書参照のハードコーディングが大丈夫なら):
UserTypeエンティティでは、UserType IDへの静的参照を作成します:
public partial class UserType
{
public const int AdminUserTypeID = 1;
public const int PlainUserTypeID = 2;
}
ユーザーエンティティには、UserType外部キーに簡単にアクセスするためのエクステンダープロパティがあります。
public partial class User
{
public int? UserTypeID
{
set
{
UserTypeReference.EntityKey = new EntityKey("UserEntities.UserType", "UserTypeID", value);
}
get
{
if (UserTypeReference.EntityKey == null)
return null;
if (UserTypeReference.EntityKey.EntityKeyValues.Count() > 0)
return (int)UserTypeReference.EntityKey.EntityKeyValues[0].Value;
else
return null;
}
}
}
最後に、新しいユーザーを作成するための使用例は次のようになります。
using(UserEntities userEntities = new UserEntitites())
{
User user = new User();
user.UserTypeID = UserType.AdminUserTypeID;
userEntities.AddToUser(user);
userEntities.SaveChanges()
}