【问题标题】:Merging two iqueryables that are projected to one entity from different tables合并从不同表投影到一个实体的两个 iqueryable
【发布时间】:2014-05-13 16:23:58
【问题描述】:

我尝试过This answerThis onethis one 来合并两个 iqueryable。但我总是收到以下错误:

“Estudio”类型出现在单个 LINQ to Entities 查询中的两个结构不兼容的初始化中。一个类型可以在同一个查询的两个地方初始化,但前提是在两个地方都设置了相同的属性,并且这些属性的设置顺序相同。

我使用以下代码从两个不同但相似的实体框架实体(EXAMEN 和 EXPLORACION)映射到我的域实体 Estudio。

IQueryable<Estudio> listExamen = context.Set<EXAMEN>().Project().To<Estudio>();
IQueryable<Estudio> listExploracion = context.Set<EXPLORACION>().Project().To<Estudio>();

var listCombined = listExamen.Concat(listExploracion);

是否有通过合并两个列表来生成 IQueryable(不可枚举)?如果使用 AsEnumerable(),则在内存上执行以下过滤器(Order、Take 等)。所以我需要合并列表,但仍然能够在不执行查询的情况下将过滤器应用于合并列表。

//This will force the next condition is executed on memory
    var listCombined = listExamen.AsEnumerable().Concat(listExploracion);

这可能吗?

【问题讨论】:

    标签: c# linq entity-framework merge iqueryable


    【解决方案1】:

    我会尝试在您的 linq 查询中将您的数据选择为匿名类型,执行联合,然后添加您的条件。

    var listExamen = context.Examen
        .Select(x => new { x.Prop1, x.Prop2, ... }); // Add properties
    
    var listExploracion = context.Exploraction
        .Select(x => new { x.Prop1, x.Prop2, ... }); // Add identical properties
    
    var listCombined = listExamen.Concat(listExploracion);
    
    var whereAdded = listCombines
        .Where(x => x.Prop1 == someValue);
    var result = whereAdded
        .Skip(skipCount)
        .Take(takeCount)
        .ToList();
    

    注意:我不知道您是否可以将公用表表达式(跳过/获取的 SQL 必要性)与联合查询结合使用

    注意:我已经更改了用于创建表达式的方法,因为我不知道你的方法(ProjectTo

    所以我认为解决方案不是转换为特定类型,而是转换为匿名类型,因为这可能可以转换为 SQL。

    警告:未测试

    【讨论】:

    • 听起来不错!我目前正在尝试相同的方法,但使用自定义映射。我会通知你进展情况。
    • 我使用您的方法,但添加了自定义映射。 Automapper 不是要走的路。谢谢!
    • @amalbala 我在 AutoMapper 中也发现了这个错误。你的解决方案是什么?
    • 最后我在数据库上创建了一个视图来创建联合,然后在 ORM 上使用这个视图。 Automapper 只是将实体映射到“联合”模型
    【解决方案2】:

    我的解决方案是修改我的映射代码。我不得不一次投影整个实体,而不是使用单个基于属性的映射器,确保所有属性都以相同的顺序给出。

    所以,而不是 ForMember 语法:

    Mapper.CreateMap<Client, PersonResult>()
        .ForMember(p => p.Name, cfg => cfg.MapFrom(c => c.Person.FirstName + " " + c.Person.LastName))
        ...
    

    我使用了ProjectUsing 语法:

    Mapper.CreateMap<Client, PersonResult>()
        .ProjectUsing(c => new PersonResult()
        {
            Name = c.Person.FirstName + " " + c.Person.LastName
            ...
        });
    

    这一定是因为 AutoMapper 构造其投影的方式。

    【讨论】:

    【解决方案3】:

    解决此问题的一种方法是添加虚拟类型:

    class Estudio<T> : Estudio { }
    

    还有新的映射:

    Mapper.CreateMap<Estudio , Estudio>();
    Mapper.CreateMap<EXAMEN , Estudio<EXAMEN>>();
    Mapper.CreateMap<EXPLORACION, Estudio<EXPLORACION>>();
    

    需要注意的是Estudio 中的所有字段都需要一些映射值。 你不能使用忽略。返回0"" 很好。 现在我们可以这样做了:

    var a = context.Set<EXAMEN>().ProjectTo<Estudio<EXAMEN>>();
    var b = context.Set<EXPLORACION>().ProjectTo<Estudio<EXPLORACION>>();
    
    return a.ProjectTo<Estudio>().Concat(b.ProjectTo<Estudio>());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-29
      • 1970-01-01
      • 1970-01-01
      • 2013-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多