我在使用 EF 4.2 的项目中遇到以下问题。我使用 EF 5.0(在 .NET 4.0 上)制作了一个小型测试项目,以检查新版本中的问题是否相同 - 确实如此。
样品型号:
public class Order
{
public int TenantId { get; set; }
public int OrderId { get; set; }
public string Name { get; set; }
public int? CustomerId { get; set; }
public Customer Customer { get; set; }
}
public class Customer
{
public int TenantId { get; set; }
public int CustomerId { get; set; }
public string Name { get; set; }
}
使用 Fluent API 的上下文和映射:
public class MyContext : DbContext
{
public DbSet<Order> Orders { get; set; }
public DbSet<Customer> Customers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>()
.HasKey(o => new { o.TenantId, o.OrderId });
modelBuilder.Entity<Customer>()
.HasKey(c => new { c.TenantId, c.CustomerId });
modelBuilder.Entity<Order>()
.HasOptional(o => o.Customer)
.WithMany()
.HasForeignKey(o => new { o.TenantId, o.CustomerId });
}
}
这里的重要部分是使用复合外键Order
引用(可选)a ,其中第一部分同时是主键的一部分。Customer
(TenantId, CustomerId)
TenantId
(TenantId, OrderId)
我创建数据库和一个Order
...
Database.SetInitializer(new DropCreateDatabaseAlways<MyContext>());
using (var ctx = new MyContext())
{
var order = new Order { TenantId = 1, OrderId = 500, Name = "Test Order" };
ctx.Orders.Add(order);
ctx.SaveChanges();
}
......它的工作原理。数据库模式看起来符合预期(与 principalCustomer
和 principal key(TenantId, CustomerId)
以及dependent Order
and foreign key的外键关系(TenantId, CustomerId)
)。
然后我加载Order
,创建一个新的Customer
,将它分配给它并保存更改以更新和Order
之间的关系:Customer
Order
using (var ctx = new MyContext())
{
var order = ctx.Orders.Find(1, 500);
var customer = new Customer { TenantId = 1, CustomerId = 1000,
Name = "Test Customer" };
order.Customer = customer;
// order.TenantId is 1 and customer.TenantId is 1
try
{
ctx.SaveChanges();
}
catch (Exception e)
{
throw;
}
}
打电话时SaveChanges
出现InvalidOperationException
异常:
属性“TenantId”是对象的关键信息的一部分,不能修改。
堆栈跟踪是:
at System.Data.Objects.EntityEntry.VerifyEntityValueIsEditable(StateManagerTypeMetadata typeMetadata, Int32 ordinal, String memberName)
at System.Data.Objects.EntityEntry.GetAndValidateChangeMemberInfo(String entityMemberName, Object complexObject, String complexObjectMemberName, StateManagerTypeMetadata& typeMetadata, String& changingMemberName, Object& changingObject)
at System.Data.Objects.EntityEntry.EntityMemberChanging(String entityMemberName, Object complexObject, String complexObjectMemberName)
at System.Data.Objects.EntityEntry.EntityMemberChanging(String entityMemberName)
at System.Data.Objects.ObjectStateEntry.System.Data.Objects.DataClasses.IEntityChangeTracker.EntityMemberChanging(String entityMemberName)
at System.Data.Objects.Internal.SnapshotChangeTrackingStrategy.SetCurrentValue(EntityEntry entry, StateManagerMemberMetadata member, Int32 ordinal, Object target, Object value)
at System.Data.Objects.Internal.EntityWrapper`1.SetCurrentValue(EntityEntry entry, StateManagerMemberMetadata member, Int32 ordinal, Object target, Object value)
at System.Data.Objects.DataClasses.EntityReference.UpdateForeignKeyValues(IEntityWrapper dependentEntity, IEntityWrapper principalEntity, Dictionary`2 changedFKs, Boolean forceChange)
at System.Data.Objects.DataClasses.RelatedEnd.Add(IEntityWrapper wrappedTarget, Boolean applyConstraints, Boolean addRelationshipAsUnchanged, Boolean relationshipAlreadyExists, Boolean allowModifyingOtherEndOfRelationship, Boolean forceForeignKeyChanges)
at System.Data.Objects.ObjectStateManager.PerformAdd(IEntityWrapper wrappedOwner, RelatedEnd relatedEnd, IEntityWrapper entityToAdd, Boolean isForeignKeyChange)
at System.Data.Objects.ObjectStateManager.PerformAdd(IList`1 entries)
at System.Data.Objects.ObjectStateManager.DetectChanges()
at System.Data.Objects.ObjectContext.DetectChanges()
at System.Data.Entity.Internal.InternalContext.DetectChanges(Boolean force)
at System.Data.Entity.Internal.InternalContext.GetStateEntries(Func`2 predicate)
at System.Data.Entity.Internal.InternalContext.GetStateEntries()
at System.Data.Entity.Infrastructure.DbChangeTracker.Entries()
at System.Data.Entity.DbContext.GetValidationErrors()
at System.Data.Entity.Internal.InternalContext.SaveChanges()
at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
at System.Data.Entity.DbContext.SaveChanges()
我看不出我会在哪里更改“钥匙的一部分” TenantId
。它的值是1
inOrder
并且是1
in Customer
。
如何使用上面的代码修改此关键属性,如何使更新正常工作?