2016-09-30 3 views
1

У меня есть некоторые проблемы с запросом LINQ на C#.Присоединиться к LINQ-запросу с предикатом

У меня в базе данных те же таблицы, которые имеют одинаковую структуру. Итак, сегодня я беспокоился о моем запросе LINQ.

Подробнее, я хочу присоединиться к некоторым таблицам с использованием предикатов.

У меня есть функция, которая имеет два параметра. Первый параметр - это какой-то контекст (например, он может быть ProductContext, CarContext, CatContext и т. Д.).

Второй параметр - List<something>, который я присоединяюсь к моему первому параметру - Контекст.

Мне не нужен набор методов.

Я добавил образец:

public Element[] GetByIds(MyPredicateContext, Guid[] ids) 
    { 
     return 
      from id in ids 
      join element in MyPredicateContext on id equals element.Id 
      select 
       new Element 
       { 
        Id = element.Id, 
        Description = element.JobDescription, 
       }; 
    } 
+1

Почему вы хотите контекст в качестве параметра, а не таблицы? Или вы хотите оба? И я думаю, что все ваши элементы не имеют свойства JobDescription, не так ли? –

ответ

0

Если запрос является правильным, один основной вопрос, который я могу видеть это тип возвращаемого значения элементов массива в то время как вы пытаетесь вернуть IEnumerable. Возможно, выполнение .ToArray() в результирующем наборе может решить проблему.

+0

Не имеет значения для этого вопроса – Andrew

+0

Извинения, может быть, я не получил здесь проблемы, не могли бы вы объяснить дальнейшую точную ошибку, которую вы получаете. –

+0

Парень, это не ошибка. Вы читали описание?! – Andrew

0

Почему не

return MyPredicateContext.Where(element=>ids.Contains(element.Id)) 
      .Select(e=>new Element() 
      { 
       Id = element.Id, 
       Description = element.JobDescription 
      }).ToArray(); 
+0

Обратите внимание, было соединение – Andrew

0

Прежде всего, вы не можете создать новую IQueryable из массива это будет вернуться к вытягивать все в памяти и фильтрации там. Вы работаете с выражениями, а не с кодом C# при LINQ с SQL, это будет работать только в памяти (IEnumerable). Ваш запрос будет работать в SQL, если вы делаете это как этот

from element in MyPredicateContext 
where ids.Contains(element.Id) 
select new Element 
       { 
        Id = element.Id, 
        Description = element.JobDescription, 
       } 

Учитывая, что тип IQueryable где T представляет собой интерфейс или класс. Метод конечных будет выглядеть как этот

public interface IElement 
     { 
      Guid Id { get; } 
      string JobDescription { get; } 
     } 

     public Element[] GetByIds<T>(IQueryable<T> myPredicateContext, Guid[] ids) where T:IElement 
     { 
      return (from element in myPredicateContext 
        where ids.Contains(element.Id) 
        select new Element 
            { 
             Id = element.Id, 
             Description = element.JobDescription, 
            }).ToArray(); 

     } 

Есть способы сделать это без каких-либо дженериков, но они немного более продвинутый и будет трудно поддерживать.

Вот метод, который будет работать на всех типах T, и правильный IQueryable будет производить хороший sql, как я уже указывал, немного более продвинутый, и вам нужно будет найти, как работает выражение.

public static Element[] GetById<T, Tkey>(IQueryable<T> items,Tkey[] ids) 
     { 
      var type = typeof(T); 
      ParameterExpression param = Expression.Parameter(type); 
      var list = Expression.Constant(ids); 
      //The names of the properties you need to get if all models have them and are named the same and are the same type this will work 
      var idProp = Expression.Property(param, "Id"); 
      var descriptionProp = Expression.Property(param, "JobDescription"); 

      var contains = typeof(Enumerable).GetMethods().First(m => m.Name == "Contains" && m.GetParameters().Count() == 2).MakeGenericMethod(typeof(Tkey)); 
      var where = Expression.Lambda<Func<T, bool>>(Expression.Call(contains, list, idProp), param); 

      return (items. 
       Where(where). 
       Select(Expression.Lambda<Func<T, Element>>(
        Expression.MemberInit(
        Expression.New(typeof(Element)), 
         Expression.Bind(typeof(Element).GetProperty("Id"), idProp), 
         Expression.Bind(typeof(Element).GetProperty("Description"), descriptionProp)), 
         param))).ToArray(); 
     } 

Вызов GetById(items, new Guid[] { Guid.NewGuid() })

+0

Обратите внимание, было соединение – Andrew

+0

@Andrew 'Contains' делает то же самое, что и ваше соединение в этом случае. –

+0

@Filip Cordas. Хорошо, извините, это моя ошибка, но как класс из DataBase может быть унаследован от IElement? – Andrew

 Смежные вопросы

  • Нет связанных вопросов^_^