LINQ-to-entities generic == Обхід

Я маю наступний запит LINQ-to-entities

IQueryable> GetFirstOperationsForEveryId
    (IQueryable> ItemHistory)
{
    var q = (from h in ItemHistory
             where h.OperationId ==
                (from h1 in ItemHistory
                 where h1.GenericId == h.GenericId
                 select h1.OperationId).Min()
             select h);
    return q;
}

ItemHistory is a generic query. It can be obtained in the following way

var history1 = MyEntitiySet1.Select(obj =>
    new History{ obj.OperationId, GenericId = obj.LongId });
var history2 = AnotherEntitiySet.Select(obj =>
    new History{ obj.OperationId, GenericId = obj.StringId });

In the end of all I want a generic query being able to work with any entity collection convertible to History.

Проблема полягає в тому, що код робить не компілювати через порівняння GenericId у внутрішньому запиті (оператор == 'не може бути застосований до операндів типу' T 'та' T ').

Якщо я зміню == до h1.GenericId.Equals (h.GenericId) , я отримаю такий NotSupportedException :

Неможливо віддати тип "System.Int64" для введення "System.Object". LINQ для об'єктів підтримує тільки типи примітивних типів даних об'єкта даних об'єктів.

Я спробував групувати замість підзапиту і приєднатися до результатів.

IQueryable> GetFirstOperationsForEveryId
    (IQueryable> ItemHistory)
{
    var grouped = (from h1 in ItemHistory
                   group h1 by h1.GenericId into tt
                   select new
                   {
                        GenericId = tt.Key,
                        OperationId = tt.Min(ttt => ttt.OperationId)
                   });

    var q = (from h in ItemHistory
             join g in grouped
                on new { h.OperationId, h.GenericId }
                equals new { g.OperationId, g.GenericId }
             select h);
    return q;
}

Він компілює, оскільки GenericId порівнюється з ключовим словом equal , але він працює, але запит з реальними даними занадто повільний (він працював 11 годин на спеціальному сервері postgresql).

Існує можливість побудувати ціле вираз для зовнішнього заяви. Але код буде занадто довгим і незрозумілим.

Чи існують які-небудь прості способи для порівняння рівності з генериками в LINQ-до-сутностях?

2

4 Відповіді

Спробуйте це, я думаю, він повинен виконати те, що ви хочете без додаткового запиту/приєднання

IQueryable> GetFirstOperationsForEveryId
    (IQueryable> ItemHistory)
{
  var q = from h in ItemHistory
          group h by h.GenericId into tt
          let first = (from t in tt
                        orderby t.GenericId
                        select t).FirstOrDefault()
          select first;

  return q;
}
1
додано
Дуже елегантне рішення! На жаль, ще не реалізовано в Npgsql (станом на 2.0.11.92). System.Data.EntityCommandCompilationException: Під час підготовки визначення команди сталася помилка. ---> System.NotImplementedException: метод або операція не реалізована. Моя актуальна проблема полягала в тому, що я забув створити індекси. Ось чому запит групи + приєднався до 11 годин. За допомогою індексів вона працює досить швидко.
додано Автор Mike, джерело

Ви також можете встановити загальне обмеження на T для інтерфейсу IItemHistory, яке реалізує властивість GenericId і OperationId.

0
додано

Моє запитання вже містить рішення. Другий метод з приєднанням групи + добре працює, якщо таблиця правильно індексована . Це займає 3,28 секунди для вилучення 370k рядків з таблиці бази даних. Насправді в неродивному варіанті перший запит повільний на postgresql, ніж другий. 26,68 секунди проти 4,75.

0
додано
IQueryable> GetFirstOperationsForEveryId
(IQueryable> ItemHistory)
{
var grouped = (from h1 in ItemHistory
               group t by h1.GenericId into tt
               select new
               {
                    GenericId = tt.Key,
                    OperationId = tt.Min(ttt => ttt.OperationId)
               });

var q = (from h in ItemHistory
         join g in grouped
            on new { h.OperationId, h.GenericId }
            equals new { g.OperationId, g.GenericId }
         select h);
return q;
}
0
додано
Яка відмінність від того, що я опублікував?
додано Автор Mike, джерело
var chat = new Chat();
var chat = new Chat();
642 учасників

Обсуждение вопросов по C# / .NET / .NET Core / .NET Standard / Azure Сообщества-организаторы: — @itkpi — @dncuug