Линк выражения дерева много ко многим IQueryable расширение - PullRequest
1 голос
/ 09 марта 2020

Я сейчас работаю над приложением asp. net web api 2. Пожалуйста, помните, мой опыт в php, js, css и так далее, а не c#.

Я надеюсь, что кто-то может помочь мне с моим универсальным расширением IQueryable, которое использует дерево выражений Linq.

У меня есть 3 таблицы (Entity Framework).

Сделки

Id,Name

ProductTrades (таблица ссылок)

Id,Trade_Id,Product_Id

Продукты

Id,Code

Мне нужно вернуть все сделки, в которых есть хотя бы один код продукта из списка кодов продуктов, переданных в виде переменной

У меня есть эта работа нормально со следующими

list<string> tocheck = new list<string>("productcode1","productcode2");
var trades = db.Trades.SqlQuery(
               "Select * from Trades T " +
               "left join ProductTrades PT on T.Id = PT.Trade_Id " +
               "left join Products P on PT.Product_Id = P.Id " +
               "where P.Code in (@prod)", new SqlParameter("@prod", String.Join(",", tocheck))).ToList();

Однако я хотел бы использовать дерево выражений Linq для достижения этого, чтобы сделать его обобщенным c

См. Ниже мою попытку (я собрал это, используя несколько источников, пытаясь изучить его)

public static IQueryable<T> FilterWhereItemIn<T>(this IQueryable<T> queryable, string propertyOrFieldName, List<string> values)
        {
            var elementType = typeof(T);
            var parameterExpression = Expression.Parameter(elementType);
            var propertyOrFieldExpression = propertyOrFieldName.Split('.').Aggregate((Expression)parameterExpression, Expression.PropertyOrField);
            var method = typeof(List<string>).GetMethod("Contains", new Type[] { typeof(string) });
            var someValue = Expression.Constant(values, typeof(List<string>));
            var containsExpression = Expression.Call(propertyOrFieldExpression, method, someValue);
            var selector = Expression.Lambda<Func<T, bool>>(containsExpression, parameterExpression);
            return queryable.Where(selector);
        }

и я вызываю это со следующим (IQueryable запрашиваемый тип торговли)

list<string> tocheck = new list<string>("productcode1","productcode2");
queryable.FilterWhereItemIn("Products.Code", tocheck );

Однако я получаю сообщение об ошибке, что «Код» не существует. Я предполагаю, что это потому, что Продукция - это коллекция. Кто-нибудь знает, как этого добиться.

(PS Извините, этот пост был немного срочно)

Ответы [ 3 ]

0 голосов
/ 10 марта 2020

После обсуждения с DavidG (спасибо) похоже, что я пошел по неверному пути, пытаясь достичь своей цели.

мне не нужно было создавать расширение, и я мог добиться нужных результатов, используя простой однострочный запрос linq.

var trades = new List<Trade>();
trades = db.Trades.Where(t => t.Products.Any(p => getRequest.products.Contains(p.Code))).ToList();

getRequest - это простой класс, который имеет public list<string> products { get; set; } геттер и сеттер

0 голосов
/ 12 апреля 2020

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

public static class WhereGenerator
    {
        // Where Generator For Contains
        public static IQueryable<T> FilterWhereItemIn<T>(this IQueryable<T> queryable, string propertyOrFieldName, List<string> values)
        {
            var elementType = typeof(T);
            var parameterExpression = Expression.Parameter(elementType);
            var propertyOrFieldExpression = propertyOrFieldName.Split('.').Aggregate((Expression)parameterExpression, Expression.PropertyOrField);
            var method = typeof(List<string>).GetMethod("Contains", new Type[] { typeof(string) });
            var someValue = Expression.Constant(values, typeof(List<string>));
            var containsExpression = Expression.Call(someValue, method, propertyOrFieldExpression);
            var selector = Expression.Lambda<Func<T, bool>>(containsExpression, parameterExpression);
            return queryable.Where(selector);
        }
    }

        public class Products
        {
            public int Id { get; set; }
            public string Code { get; set; }
        }
        public class Trades
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }
        public class ProductTrades
        {
            public int Id { get; set; }
            public Trades Trade { get; set; }
            public Products Product { get; set; }
        }

        static void Main(string[] args)
        {
            List<ProductTrades> lpt2 = new List<ProductTrades> { new ProductTrades { Id = 1, 
                                                                                     Trade = new Trades { Id = 13, Name = "trade2" }, 
                                                                                     Product = new Products { Code = "productcode1", Id = 1 } },
                                                                new ProductTrades { Id = 11,
                                                                                     Trade = new Trades { Id = 13, Name = "trade4" },
                                                                                     Product = new Products { Code = "productcode2", Id = 2 } },
                                                                new ProductTrades { Id = 1,
                                                                                     Trade = new Trades { Id = 13, Name = "trade2" },
                                                                                     Product = new Products { Code = "productcode5", Id = 1 } }
                                                              };

            List<string> tocheck = new List<string>() { "productcode1", "productcode2" };
            var r1 = lpt2.AsQueryable().FilterWhereItemIn("Product.Code", tocheck);
            var r2 = r1.ToList();
}

0 голосов
/ 09 марта 2020

Параметры в строке Expression.Call перепутаны. Вы должны вызывать метод Contains для списка, а не для свойства. Используйте это вместо:

var containsExpression = Expression.Call(someValue, method, propertyOrFieldExpression);
...