【问题标题】:Duplicating Entity Framework entities复制实体框架实体
【发布时间】:2020-04-11 12:34:27
【问题描述】:

我有这个 EF 查询:

var records = mydata.Where(a => some condition).ToList();

记录是Record 对象的列表。 Record 是一个数据库表,它具有称为“关系”的一对多关系。

EF 对象将该成员变量表示为Collection<Relation>

在上面的where 之后,我看到“关系”成员变量包含18 个实体的集合。

我需要复制那些Record 对象,以便我先将它们分离,这样:

var detached = this.DetachEntities(records, db, "RecordId");

this.DetachEntities 是这样定义的:

    private T DetachEntity<T>(T entity, Repositories.GestionActivosEntities db, string keyName) where T : class
    {
        db.Entry(entity).State = EntityState.Detached;

        if (entity.GetType().GetProperty(keyName) != null)
        {
            entity.GetType().GetProperty(keyName).SetValue(entity, 0);
        }

        return entity;
    }

    private List<T> DetachEntities<T>(List<T> entities, Repositories.GestionActivosEntities db, string keyName) where T : class
    {
        foreach (var entity in entities)
        {
            this.DetachEntity(entity, db, keyName);
        }

        return entities;
    }

分离实体后,我正在做:

db.Record.AddRange(detached);

问题是,在我分离列表后,关系也没有被复制,导致“关系”成员变量不包含任何元素。

分离后如何保留关系元素?

编辑:

这显示了调试会话:

断点位于完成查询的行中。光标显示查询执行后的行。

此截图显示了子记录 ValorCampo 和 Workflow

此屏幕截图显示了分离后的实体。请注意,子记录不存在于分离的对象中

正如我所说,问题仅在于分离时。不保留儿童记录。数据库行保持不变。

【问题讨论】:

  • “关系也没有被复制”是什么意思,什么“关系”成员变量不包含元素?请edit你的问题包含一个minimal reproducible example,它可以被其他人编译和测试。
  • 我明天可以编辑问题,但我不确定这是否会有所帮助。正如我告诉你的,这是一对多的关系。 “记录”是父实体,“关系”是子项的集合。原始 Record 包含 18 个子元素。分离后,Records 包含 0 个子元素。
  • MCVE 将有所帮助,因为它显示了如何添加数据、如何使用上下文对象以及如何检查实体的数量。分离对象不会删除数据库中的行。所以 MCVE 应该清楚地表明子元素的数量不符合预期。
  • @Progman 你应该知道,关系是由实体框架自动加载的。通过执行“mydata.Where(a => some condition).ToList()”,所有关系记录都由实体框架自动加载框架。我什么都不做加载它们。顺便说一句,我认为这是因为默认情况下使用“延迟加载”。如何在第一次查询时强制加载某些关系?但只有一种关系。我对其他人不感兴趣。此外,也许你不明白这个问题。数据库中的记录不会被删除。问题是分离的对象不保留子记录。
  • 实体的关系不会自动加载,仅应请求加载。否则,当您仅加载一个实体时,您将加载整个数据库。您可以使用Include() 在查询中加载相关实体,而无需加载您不想要的实体/关系。 “延迟加载”可能不是这里的问题,但很难说。请提供清楚显示实体计数错误的 MCVE。

标签: c# entity-framework-6


【解决方案1】:

我遇到了同样的问题,不幸的是,在分离项目或实体状态更改为分离后,导航属性会丢失。

你可以做的是克隆实体 一种方法是:Context.Entry(your_entity).CurrentValues.ToObject();

但是这也不会克隆导航属性

如果你完全想克隆一个带有导航属性的对象 我实现它的最简单方法是使用 c# 的 automapper 库

下面是一个示例用法:

var config = new MapperConfiguration(cfg => cfg.CreateMap<originalObject, T>());
var mapper = new Mapper(config);
// or
var mapper = config.CreateMapper();

T  clonedObject = mapper.Map<T>(originalObject);

克隆和分离原始对象后,您可以添加

db.Record.AddRange(clonedObject );

下面是一个通用的扩展来做到这一点

public static object Map<T>(this T source)
    {
        var fullName = source.GetType().FullName;
        var sourceType = source.GetType();

        var baseType = ObjectContext.GetObjectType(source.GetType());

        var config = new MapperConfiguration(cfg =>
            cfg.CreateMap(sourceType, baseType));




        var mapper = config.CreateMapper();

        var entity = mapper.Map(source, sourceType, baseType);

        return entity;
}

你可以这样称呼它

var clonedObject = originalObject.Map();

希望这会有所帮助!

【讨论】:

  • 谢谢,但我终于使用了一个不太优雅的解决方案。我已经查询了数据库两次。然后我分离了第一个实体。最后,我从另一个附加实体重建了导航属性。
  • 如果在任何情况下都失败了,你总是可以使用上面的代码sn-p
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-06
  • 1970-01-01
相关资源
最近更新 更多