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

Eri*_*ser 4 entity-framework

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

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

这是代码:

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

我看到错误是由于主键的值被复制到新实体中.那么,如何在没有密钥的情况下复制值?

谢谢你的帮助埃里克

Ali*_*kel 7

解决方案1

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

_appDbContext 辅助方法:

    public TEntity DetachedClone<TEntity>(TEntity entity) where TEntity : class
            => Entry(entity).CurrentValues.Clone().ToObject() as TEntity;
Run Code Online (Sandbox Code Playgroud)

为您解答:

    var period2 = _tariffRepository.GetPeriodFull(period.GUID);
    var period3 = _appDbContext.DetachedClone(period2);
    _appDbContext.TariffPeriods.Add(period3);
Run Code Online (Sandbox Code Playgroud)

解决方案2

您也可以使用简单的 JSON 深度克隆功能。像魅力一样工作。我更喜欢这种方法,因为第一个解决方案涉及首先使用附加条目.Entry(),这可能是不可取的

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

(???)??? ??


Edw*_*rey 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);
Run Code Online (Sandbox Code Playgroud)


gre*_*k40 5

您可以尝试获取period2数据的克隆并在分配到period3之前修改Id

var values = db.Entry(period2).CurrentValues.Clone();
values["Id"] = 0;
db.Entry(period3).CurrentValues.SetValues(values);
Run Code Online (Sandbox Code Playgroud)