У нас есть следующее: Порядок с UserId и таблицей User.
Допустим, мы хотим кэшировать все объекты User как отключенные объекты, а затем использовать их в ASP.NET или веб-службах, таких как среда.
Поскольку среда среды использует платформы UnitOfWork и IOC, мы хотели бы избежать каких-либо манипуляций с контекстом.Как и в следующем модульном тесте:
- Получить отключенный пользовательский объект
- Создать контекст
- Создать объект заказа
- Присоединить пользователя через пользовательский объект или идентификатор
- Сохранить весь объект Порядка.
После двух дней яростного поиска в Google я не смог найти никакого решения.
Проблемы:
1.USER OBJECT
Если мы присоединяем объект пользователя (с userId = 1), при поведении по умолчанию EF думает, что это новый объект пользователя, и пытается сохранить новый объект пользователя в БД,Это дует, потому что db уже имеет userId == 1.
Возможное решение - переопределить DbContext.SaveChanges, попытаться выяснить, «отключен» ли пользователь, и принудительно присоединить его к контексту.Я не мог понять, как это сделать, потому что методы расширения EFExtensionMethods.IsAttached или EFExtensionMethods.AttachItem при вызове из SaveChanges думают, что T является объектом.
2.USER_ID
Это работает, за исключением случаев, когда вы хотите получить доступ к объекту Order.User перед сохранением и перезагрузкой всей сущности.
Поверх этого нам потребуется разделить API, поэтомуэто сохранение только с использованием идентификаторов объектов (т.е. Order.UserId), а не фактический объект (Order.User).После перезагрузки объекта мы можем использовать оба.Но я не вижу способа обеспечить его применение через API.
3.ОБА ОБЪЕКТ ПОЛЬЗОВАТЕЛЯ и USER_ID
В этом сценарии, даже если пользователь помечен как использующий UserId в качестве внешнего ключа, EF все еще пытается сохранить объект User в контексте, решая проблемы, описанные в 1.
Похоже, я что-то упустил (или многое) фундаментальное, и вопросы:
- Что бы вы порекомендовали сделать?
- Есть ли хороший и общий способсоздания EFExtensionMethods.IsAttached из DbContext.SaveChanges
- Есть ли хороший и универсальный способ создания EFExtensionMethods.AttachItem из DbContext.SaveChanges
Любая помощь очень ценится. 1055
[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;}
}