将上下文中的实体替换为同一实体的不同实例



我有一个实体没有连接到我的dbcontext。我想改变这一点。但是,已经有同一实体的另一个实例附加到dbcontext 。如果我只是添加新实体,则会收到一个错误,即已附加具有相同主键的实体。
我尝试了多种不同的变体来从dbcontext中删除旧实体,但没有任何成功。如何将旧实例替换为新实例?
注意:我不想复制值,我想将新实体的这个实例附加到dbcontext

var entity = new MyEntity { Id = 1 };
var logicalDuplicate = dbcontext.Set<MyEntity >().Local
    .FirstOrDefault(e => e.Equals(entity));
if (logicalDuplicate != null)
{
    // remove logicalDuplicate from dbcontext
}
dbcontext.MyEntity.Attach(entity);

澄清一下:我已经覆盖了Equals以检查Id而不是参考。

试试这个:

if (logicalDuplicate != null)
{
    dbcontext.Entry(logicalDuplicate).State = EntityState.Detached;
    dbcontext.MyEntity.Attach(entity);
    dbcontext.Entry(entity).State = EntityState.Modified;
}
else
{
    dbcontext.MyEntity.Add(entity);
}

如何获取相关条目

对此进行了调查,并希望与我的结果分享。我使用反射作为获取实体属性名称的简短方法。但正如海德尔@Florian提到的那样,有可能在没有反思的情况下得到它。您可以使用回答和这个。

// Found loaded related entries that can be detached later.
private HashSet<DbEntityEntry> relatedEntries;
private DbContext context;
private List<string> GetPropertiesNames(object classObject)
{
    // TODO Use cache for that.
    // From question https://stackoverflow.com/questions/5851274/how-to-get-all-names-of-properties-in-an-entity
    var properties = classObject.GetType().GetProperties(BindingFlags.DeclaredOnly |
                                                              BindingFlags.Public |
                                                              BindingFlags.Instance);
    return properties.Select(t => t.Name).ToList();
}
private void GetRelatedEntriesStart(DbEntityEntry startEntry)
{
    relatedEntries = new HashSet<DbEntityEntry>();
    // To not process start entry twice.
    relatedEntries.Add(startEntry);
    GetRelatedEntries(startEntry);
}
private void GetRelatedEntries(DbEntityEntry entry)
{
    IEnumerable<string> propertyNames = GetPropertiesNames(entry.Entity);
    foreach (string propertyName in propertyNames)
    {
        DbMemberEntry dbMemberEntry = entry.Member(propertyName);
        DbReferenceEntry dbReferenceEntry = dbMemberEntry as DbReferenceEntry;
        if (dbReferenceEntry != null)
        {
            if (!dbReferenceEntry.IsLoaded)
            {
                continue;
            }
            DbEntityEntry refEntry = context.Entry(dbReferenceEntry.CurrentValue);
            CheckReferenceEntry(refEntry);
        }
        else
        {
            DbCollectionEntry dbCollectionEntry = dbMemberEntry as DbCollectionEntry;
            if (dbCollectionEntry != null && dbCollectionEntry.IsLoaded)
            {
                foreach (object entity in (ICollection)dbCollectionEntry.CurrentValue)
                {
                    DbEntityEntry refEntry = context.Entry(entity);
                    CheckReferenceEntry(refEntry);
                }
            }
        }
    }
}
private void CheckReferenceEntry(DbEntityEntry refEntry)
{
    // Add refEntry.State check here for your need.
    if (!relatedEntries.Contains(refEntry))
    {
        relatedEntries.Add(refEntry);
        GetRelatedEntries(refEntry);
    }
}

编辑 这将找到原始产品,将其删除,然后添加新产品:

    static void UpdateDatabase() 
    {
        Context context = new Context();
        Product product1 = context.Products.Find(1);
        context.Products.Remove(product1);
        Product product2 = new Product(){ProductId = 1, Name = "Product2"};
        context.Products.Add(product2);
        context.SaveChanges();
    }

解决这个问题的最佳方法是


db 是我的数据库对象
更新价格是我的数据库实体对象
ep 是我旧的相同数据库实体对象

db.Entry(updateprice).CurrentValues.SetValues(ep);

最新更新