3

我在使用 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 Orderand foreign key的外键关系(TenantId, CustomerId))。

然后我加载Order,创建一个新的Customer,将它分配给它并保存更改以更新和Order之间的关系:CustomerOrder

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。它的值是1inOrder并且是1in Customer

如何使用上面的代码修改此关键属性,如何使更新正常工作?

4

2 回答 2

1

According to @Pawel's suggestion I've reported the problem as possible bug at Codeplex:

http://entityframework.codeplex.com/workitem/955

At the moment for the model in the question setting the foreign key properties directly instead of setting the navigation property works and doesn't throw an exception:

using (var ctx = new MyContext())
{
    var order = ctx.Orders.Find(1, 500);
    var customer = new Customer { TenantId = 1, CustomerId = 1000,
                                  Name = "Test Customer" };

    ctx.Customers.Add(customer);
    order.CustomerId = customer.CustomerId;

    try
    {
        ctx.SaveChanges();
        // No exception here
    }
    catch (Exception e)
    {
        throw;
    }
}
于 2013-03-14T20:31:33.003 回答
1

我简要地看了一下它,似乎是一个错误,EF“认为”订单上的 TenantId 发生了变化,而实际上它没有(即值是相同的)。您介意在http://entityframework.codeplex.com/上为此提交错误吗?

于 2013-03-14T16:57:44.977 回答