EF 4.1コードファーストを使用して、単一のロールを持つユーザーの単純な関係をモデル化しようとしています。EF 4.1で1対多の関係に分離されたエンティティを追加するコードファースト
System.Data:私は(クライアント・サーバー・ラウンドトリップをシミュレートするために、異なるコンテキストを使用して)別のコンテキストに新しい役割を持つ既存のユーザーを保存しようとすると、私は次の例外を取得します。 Entity.Infrastructure.DbUpdateException:関係の外部キープロパティを公開していないエンティティを保存中にエラーが発生しました。 EntityEntriesプロパティは、単一のエンティティが例外のソースとして識別できないため、nullを返します。エンティティタイプに外部キーのプロパティを公開することで、保存時の例外処理を簡単に行うことができます。詳細については、InnerExceptionを参照してください。 --->System.Data.UpdateException: 'User_CurrentRole' AssociationSetからの関係が 'Added'状態にあります。多重度の制約が与えられると、対応する 'User_CurrentRole_Source'も 'Added'状態でなければなりません。
私が期待しているのは、新しい役割が作成され、既存のユーザーと関連付けられていることです。
私は間違って何をしていますか?これはEF 4.1のコードで最初に達成できますか?エラーメッセージは、ユーザーとロールの両方が追加された状態になる必要があることを示唆していますが、私は既存のユーザーを変更しています。
重要事項:エンティティの構造を変更しないようにしたい(エンティティに表示される外部キーのプロパティを導入するなど)。データベースには、外部キーを指すようにしたい役割(それ以外の方法ではありません)。私はまた、(別の方法がない限り)セルフトラッキングエンティティに移動する準備ができていません。ここで
は実体である:
public class User
{
public int UserId { get; set; }
public string Name { get; set; }
public Role CurrentRole { get; set; }
}
public class Role
{
public int RoleId { get; set; }
public string Description { get; set; }
}
そして、ここでは、私はマッピングを使用します:
public class UserInitializer : DropCreateDatabaseAlways<UserRolesContext>
{
protected override void Seed(UserRolesContext context)
{
context.Users.Add(new User() {Name = "Bob",
CurrentRole = new Role() {Description = "Builder"}});
context.SaveChanges();
}
}
そして最後に:
public class UserRolesContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Role> Roles { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>().HasKey(u => u.UserId);
modelBuilder.Entity<Role>().HasKey(r => r.RoleId);
modelBuilder.Entity<User>().HasRequired(u => u.CurrentRole);
}
}
を私はこれでデータベースに事前ここで失敗したテストがあります:
[TestMethod]
public void CanModifyDetachedUserWithRoleAndReattach()
{
Database.SetInitializer<UserRolesContext>(new UserInitializer());
var context = new UserRolesContext();
// get the existing user
var user = context.Users.AsNoTracking().Include(c => c.CurrentRole).First(u => u.UserId == 1);
//modify user, and attach to a new role
user.Name = "MODIFIED_USERNAME";
user.CurrentRole = new Role() {Description = "NEW_ROLE"};
var newContext = new UserRolesContext();
newContext.Users.Attach(user);
// attachment doesn't mark it as modified, so mark it as modified manually
newContext.Entry(user).State = EntityState.Modified;
newContext.Entry(user.CurrentRole).State = EntityState.Added;
newContext.SaveChanges();
var verificationContext = new UserRolesContext();
var afterSaveUser = verificationContext.Users.Include(c => c.CurrentRole).First(u => u.UserId == 1);
Assert.AreEqual("MODIFIED_USERNAME", afterSaveUser.Name, "User should have been modified");
Assert.IsTrue(afterSaveUser.CurrentRole != null, "User used to have a role, and should have retained it");
Assert.AreEqual("NEW_ROLE", afterSaveUser.CurrentRole.Description, "User's role's description should have changed.");
}
}
}
確かにこれは、私がモデルマッピングを定義した方法で紛失していると思われるシナリオです。
ありがとうございますLadislavさん、私が記述したオブジェクトモデル(つまり、STEなし、FKプロパティなし)で、このシナリオをEFコードファーストで簡単にサポートしているとは言いがたいです。プロパティとしてFKを導入することは、変更を追跡して手動でマージするのと同様に、厄介な回避策のように思えます。幸いにも、これはプロジェクトの初期段階であるため、NHibernateを評価してより適切かどうかを確認することができます。 –