以下があります。UserIdとUserテーブルで注文します。Entity Framework 4.1でキャッシュされた非接続エンティティをアタッチするコード
すべてのUserオブジェクトを切断されたエンティティとしてキャッシュし、ASP.NETやWebサービスなどの環境で使用するとします。
環境はUnitOfWorkとIOCフレームワークを使用しているため、コンテキスト操作は避けたいと考えています。ユニットテストは次のように:
-
切断されたユーザオブジェクト
- が
- コンテキストを作成しなさいOrderオブジェクト
- を作成したユーザオブジェクトかID
- を介してユーザを接続しますが、全体Orderオブジェクトを永続化します。
激しいGoogle検索の2日後、解決策が見つかりませんでした。
問題は、次のとおりです。
1.ユーザーオブジェクト
我々はEFが新しいユーザーであると考えているデフォルトの動作で、(= 1 userIdを持つ)ユーザーオブジェクトを装着している場合新しいユーザオブジェクトをdbに永続化しようとしています。これは、dbが既にuserId == 1を持っているために吹き飛ばされます。
可能な解決策は、DbContext.SaveChangesをオーバーライドして、ユーザーが「切り離され」、コンテキストに強制的に添付するかどうかを試してみることです。 SaveChangesから呼び出されたときに拡張メソッドEFExtensionMethods.IsAttachedまたはEFExtensionMethods.AttachItemがTがオブジェクトだと思うので、その方法を理解できませんでした。
2. USER_ID
これは、あなたが全体のエンティティを永続化し、リロードする前にOrder.Userオブジェクトにアクセスしたい場合を除き、動作します。
さらに、実際のオブジェクト(Order.User)ではなくオブジェクトのID(つまりOrder.UserId)を使用して保存するように、APIを分割する必要があります。オブジェクトをリロードしたら、両方を使うことができます。しかし、私は実際にAPIを通してそれを強制する方法がないのがわかります。
3.両方のユーザーオブジェクトとユーザーが外部キーとしてユーザーIDを使用するものとしてマークされている場合でも、このシナリオで
USER_IDは、EFはまだ1で説明した問題を打つコンテキストにユーザーオブジェクトを保存しようとしています。
私は基本的な何か(またはロット)を欠けているとの質問があるように見える:
- あなたが行うことをお勧めでしょうか?
- DbContext.SaveChanges
- からEFExtensionMethods.IsAttached作品を作る素晴らしく、一般的な方法はありDbContextからEFExtensionMethods.AttachItem作品を作る素晴らしく、一般的な方法がありますです。SaveChanges
何か助けていただければ幸いです。
[TestMethod]
public void Creating_Order_With_Both_User_And_Id()
{
int userCount = CountAll<User>();
User user;
using (var db = GetContext()) { user = db.Users.AsNoTracking().First(); }
using (var db = GetContext())
{
var o = CreateOrder();
o.OrderUser = user; // attach user entity
o.UserId = user.UserID; // attach by id
db.Orders.Add(o);
db.SaveChanges();
}
int newUserCount = CountAll<User>();
Assert.IsTrue(userCount == newUserCount, string.Format("Expected {0} got {1}", userCount, newUserCount));
}
コンテキストとクラス:
public class User
{
public User() {}
public int UserID {get;set;}
public string UserName {get;set;}
}
public class Order
{
public Order() { }
public int OrderID { get; set; }
public DateTime OrderDate { get; set; }
public string OrderName { get; set; }
public int UserId { get; set; }
public virtual User OrderUser { get; set; }
}
public class OrderConfiguration : EntityTypeConfiguration<Order>
{
public OrderConfiguration()
{
this.ToTable("ORDERS");
this.Property(x => x.OrderName).HasMaxLength(200);
this.HasRequired(u => u.OrderUser).WithMany().HasForeignKey(u => u.UserId);
}
}
public static class EFExtensionMethods
{
// does not work, when called from DbContext.SaveChanges thinks T is an Object.
public static bool IsAttached<T>(this PPContext db, T entity) where T: class
{
return db.Set<T>().Local.Any(e => e == entity);
}
// does not work, when called from DbContext.SaveChanges thinks T is an Object.
public static void AttachItem<T>(this PPContext db, T entity) where T: class
{
db.Set<T>().Attach(entity);
}
}
public class PPContext : DbContext
{
public PPContext() : base() { }
public PPContext(DbConnection connection) : base(connection, true) { }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Configurations.Add(new OrderConfiguration());
}
public override int SaveChanges()
{
var modified = ChangeTracker.Entries().Where(e => e.State == EntityState.Modified || e.State == EntityState.Added);
foreach (var item in modified)
{
????
}
}
public DbSet<User> Users {get;set;}
}
これは素晴らしい解決策です! – Slauma
キャッシュされたアイテムはすべて不変ですか?キャッシュされているもののように見えるので、変更することはできませんか? IsSeedingフラグで何かしていますか? – Jafin
このエクササイズの範囲では、キャッシュの不変性は考慮されません。そして、私はそれについてもっと考えるほど、重要ではありません。本当に :) – b0rg