如何在Entity Framework Core中克隆实体?

13

我正在尝试使用SetValues方法克隆一个实体,但是我收到以下错误:

实体类型'TariffPeriod'的实例无法跟踪,因为已经有另一个具有相同{'Id'}键值的实例正在被跟踪。在附加现有实体时,请确保只附加具有给定键值的一个实体实例。

这是代码:

var period2 = _tariffRepository.GetPeriodFull(period.GUID);
var period3 = new TariffPeriod();
_appDbContext.TariffPeriods.Add(period3);
_appDbContext.Entry(period3).CurrentValues.SetValues(period2);

我看到错误是由于主键值被复制到新实体中导致的。那么,如何在不复制键的情况下复制值?

谢谢你的帮助 Eric


你能够将 period2 分离吗?然后在 Add 和 SetValue 之间将其 Id 设置为 period3 的 Id 吗? - H H
3个回答

18

您可以尝试获取period2数据的副本,并在分配给period3之前修改其Id

var values = db.Entry(period2).CurrentValues.Clone();
values["Id"] = 0;
db.Entry(period3).CurrentValues.SetValues(values);

16

解决方案1

这是基于@grek40的解决方案的我的解决方案,添加了强制转换以避免字符串字面量,并允许未来重构。

_appDbContext 辅助方法:

    public TEntity DetachedClone<TEntity>(TEntity entity) where TEntity : class
            => Entry(entity).CurrentValues.Clone().ToObject() as TEntity;

针对您的问题:

    var period2 = _tariffRepository.GetPeriodFull(period.GUID);
    var period3 = _appDbContext.DetachedClone(period2);
    _appDbContext.TariffPeriods.Add(period3);

解决方案2

也可以使用一个简单的JSON深度克隆函数。这个方法十分好用。我更喜欢这种方法,因为第一种解决方案涉及到先使用.Entry()附加条目,这可能不是理想的。

    public static T Clone<T>(T source)
    {
        var serialized = JsonConvert.SerializeObject(source);
        return JsonConvert.DeserializeObject<T>(serialized);
    }

(ノ◕ヮ◕)ノ✲゚。⋆


如果你担心字符串字面量,你可以直接使用 nameof()。 - mattmanser

6

将旧时期的值复制到新时期,然后使用唯一值(在本例中为主键)设置属性,最后将实体添加到DbContext中。

var period2 = _tariffRepository.GetPeriodFull(period.GUID);
var period3 = new TariffPeriod();
_appDbContext.Entry(period3).CurrentValues.SetValues(period2);
period3.Id = 0;
_appDbContext.TariffPeriods.Add(period3);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接