【问题标题】:Set value as not modified if property value is equal如果属性值相等,则将值设置为未修改
【发布时间】:2017-04-21 00:56:53
【问题描述】:

我在将子实体从一个父实体转移到另一个父实体时遇到问题,因为实体子实体有一个复合主键,它也是外键的一部分

从技术上讲,它的问题与 Entity Framework: Cancel a property change if no change in value

但是 8 年过去了,现在应该还有其他一些解决方案吗?

到目前为止,我想出的最佳解决方案是:

    public void CleanModified()
    {
        foreach (var entityEntry in ChangeTracker.Entries()
                                .Where(w => w.State.HasFlag(EntityState.Modified)))
        {
            foreach (var currentValuesPropertyName in entityEntry.CurrentValues
                                                                    .PropertyNames)
            {
                var nop = entityEntry.Property(currentValuesPropertyName);

                if (!nop.IsModified)
                    continue;

                if (Object.Equals(nop.CurrentValue, nop.OriginalValue))
                    nop.IsModified = false;
            }
        }
    }

遗憾的是,这不起作用,只是抛出了我在 nop.IsModified = false; 上首先遇到的相同异常

The property '[CompositeKeyProperty]' is part of the object's key information 
and cannot be modified

我没有使用 T4 进行任何操作,所以我不知道在这种情况下是否可以帮助我?

添加了以下示例:

实体

public class Parent
{
    public int TenantId { get; set; }
    public int Id { get; set; }

    public virtual ICollection<Child> Children { get; set; }
}

public class Child
{
    public int TenantId { get; set; }
    public int Id { get; set; }
    public int ParentId { get; set; }

    public virtual Parent Parent { get; set; }
}

映射

public class ParentConfiguration : EntityTypeConfiguration<Parent>
{
    public ParentConfiguration()
    {
        HasKey(k => new { k.TenantId, k.Id });

        Property(p => p.TenantId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

        Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    }
}

public class ChildConfiguration : EntityTypeConfiguration<Child>
{
    public ChildConfiguration()
    {
        HasKey(k => new { k.TenantId, k.Id });

        Property(p => p.TenantId).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);

        Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

        HasRequired(r => r.Parent).WithMany(m => m.Children)
            .HasForeignKey(f => new { f.TenantId, f.ParentId });
    }
}

程序

public void Main()
{
    //Just example, fetched from database in real code
    Parent parentOld = new Parent
    {
        TenantId = 1,
        Id = 1,
        Children = { new Child { TenantId = 1, Id = 1, ParentId = 1 } }
    };

    Parent parentNew = new Parent { TenantId = 1, Id = 2 };

    //Move child from oldParent to newParent
    foreach (var parentOldChild in parentOld.Children)
    {
        //Throws 'The property 'TenantId' is part of the object's key information 
        //and cannot be modified'
        parentOldChild.Parent = parentNew; 
    }
}

【问题讨论】:

  • 您是否不小心多次引用相同的ChangeTracker 对象来检查修改状态(通过不同的上下文)?此错误通常发生在 foreach 循环中,并通过在循环体中分配该对象的新实例来解决。
  • @TetsuyaYamamoto 不,它都在同一个上下文中,访问直接路由到底层 DbContext

标签: c# entity-framework entity-framework-6 composite-key change-tracking


【解决方案1】:

错误告诉您问题是因为您试图设置作为实体键列一部分的字段的IsModified 状态。您确定您正在查看的实体不是新实体吗?这可能是CurrentValue 等于OriginalValue 的情况,但IsModified 仍然为真且无法更改。

【讨论】:

  • 添加了更多示例代码,第一个示例代码尝试还原第二个示例导致的更改,通过触摸“TenantId”会触发 changetracker 中的更改更新
  • TenantId 是表键的一部分吗?
  • 是的,我已经用一个简化的例子更新了帖子
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多