在联合查询中选择子集合

问题描述 投票:0回答:2

我正在尝试使用实体框架从数据库中选择对象为匿名类型。使用 Union 并选择子集合时,出现异常:

System.ArgumentException:“Distinct”操作无法应用于指定参数的集合 ResultType。

我的模型包含源自

BaseType
的多种类型。此基本类型引用
RefType
,其中包含
ItemType
的集合。从
BaseType
派生的类型存储在单独的表中,即 Union。

查询如下所示:

var q1 = ctx.Set<Type1>().Select(x => new { x.Id, x.Ref.Items });
var q2 = ctx.Set<Type2>().Select(x => new { x.Id, x.Ref.Items });
q1.Union(q2).ToList();

但是要重现该错误,您甚至可以合并相同类型的查询,只要您选择一个集合即可。

我会在联合之后进行选择,但是要联合

Type1
Type2
等。我必须将它们强制转换为
BaseType
,这在 LINQ-to-SQL 中是不允许的。

有什么方法可以在同一个查询中执行此操作吗?

entity-framework entity-framework-6
2个回答
3
投票

ExpressionConverter
尝试将表达式
q1.Union(q2)
转换为 SQL 时,实体框架的查询生成管道会出现异常。

在有效的查询中,您将看到 EF 向 SQL 查询添加了

DISTINCT
子句。具有集合属性 (
x.Ref.Items
) 的类型不会作为
Distinct
操作的有效参数传递,并且 EF 会引发您看到的异常。

不幸的是,使用

Concat
代替
Union
并不是有效的解决方法。 EF也会抛出异常:

不支持嵌套查询。操作1='UnionAll' 操作2='MultiStreamNest'

这意味着根本不支持连接包含具有集合属性的类型的嵌套查询。

所以你必须在记忆中做

Union

var result = q1.AsEnumerable() // Continues the query in memory
               .Union(q2).ToList();

C# 在等同包含集合的匿名类型方面没有任何问题:它只是认为任何集合成员与另一个集合成员不相等。这确实意味着查询可以生成包含非唯一结果的集合(相同的

Id
,相同的
Items
),这在依赖于
Union
的隐式
Distinct
时可能是不可预期的。


0
投票

我不确定为什么,由于某种原因,distinct 失败了,也许是因为它是匿名类型,而且它仍然是

IQueryable
,我建议触发这样的查询

var q1 = ctx.Set<Type1>()
            .Select(x => new { x.Id, x.Ref.Items })
            .ToList<object>();

var q2 = ctx.Set<Type2>()
            .Select(x => new { x.Id, x.Ref.Items })
            .ToList<object>();

q1.Union(q2).ToList();

请注意,在这种情况下,

Distinct
将检查所有属性是否相等,这意味着如果两个对象具有相同的 id 但不同的项目,则两者都会存在。

如果你不关心不同的值,你也可以使用 concat

如果你关心distinct并且第一个选项不起作用,你可以使用group by并实现你自己的distinct,像这样

var q1 = ctx.Set<Type1>()
            .Select(x => new { Id = x.Id, Items = x.Ref.Items });

var q2 = ctx.Set<Type2>()
            .Select(x => new { Id = x.Id, Items = x.Ref.Items });

// this will group by id, and select the first object items
var qFinal = q1.Concat(q2)
               .GroupBy(e => e.id)
               .Select(e => new { e.key, e.First().Items })
               .ToList();

也许你不想要

First()
,你想用什么就用什么

© www.soinside.com 2019 - 2024. All rights reserved.