Выбор подколлекций в Union-Query - PullRequest
0 голосов
/ 08 мая 2018

Я пытаюсь выбрать объекты из базы данных с Entity Framework в анонимный тип. При использовании объединения и выборе подколлекции я получаю исключение:

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.

Есть ли способ сделать это в том же запросе?

Ответы [ 2 ]

0 голосов
/ 10 мая 2018

Исключение возникает из конвейера генерации запросов Entity Framework, когда ExpressionConverter пытается преобразовать выражение q1.Union(q2) в SQL.

В действительном запросе вы увидите, что EF добавляет в запрос SQL предложение DISTINCT. Тип со свойствами коллекции (x.Ref.Items) не передается в качестве допустимого аргумента для операции Distinct, и EF выдает исключение, которое вы видите.

К сожалению, использование Concat вместо Union недопустимо. EF также сгенерирует исключение:

Вложенный запрос не поддерживается. Operation1 = 'UnionAll' Operation2 = 'MultiStreamNest'

Это означает, что просто не поддерживается объединение вложенных запросов, содержащих типы со свойствами коллекции.

Итак, вы должны сделать Union в памяти:

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

C # не имеет проблем с приравниванием анонимных типов, содержащих коллекции: он просто считает, что любой член коллекции не равен другому члену коллекции. Это означает, что запрос может создать коллекцию, содержащую неуникальные результаты (такие же Id, те же Items), которые нельзя ожидать, полагаясь на неявное Union Distinct.

0 голосов
/ 08 мая 2018

Я не уверен, почему по какой-то причине происходит сбой по-разному, может быть, потому что это анонимный тип, и он все еще IQuerable, я бы предложил запустить запрос примерно так:

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 проверит на равенство всех свойств, то есть, если 2 объекта имеют одинаковый идентификатор, но разные элементы, оба будут там.

если вас не интересуют разные значения, вы также можете использовать concat

, если вам небезразличны разные значения и первая опция не работает, вы можете использовать группуи реализовать свой собственный, что-то вроде этого

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(), вы можете использовать все, что вы хотите

...