рефакторинг выражения LINQ IQueryable для удаления дублированных частей запросов - PullRequest
7 голосов
/ 20 апреля 2009

У меня есть несколько запросов linq с избыточностью, которые я хотел бы выделить из одного куска кода. Это совместные эксперименты, которые являются IQueryable, и важно, чтобы запрос не оценивался раньше, чем без рефакторинга.

Вот упрощенный запрос:

var result = 
from T in db.Transactions
join O in db.Orders on T.OrderID equals O.OrderID
join OD in db.OrderDetails on O.OrderID equals OD.OrderID into OrderDetails
let FirstProductBought = OrderDetails.First().Select(OD => OD.Product.ProductName)
select new
{
  TransactionID = T.TransactionID,
  OrderID = O.OrderID,
  FirstProductBought = FirstProductBought
};

Что я хочу выделить, так это логику «дан заказ, какой продукт куплен первым». Я использую ту же логику в других запросах. Как я могу выделить его в общий метод?

Как правило, для повторного использования кода и IQueryables я смог сделать код, который принимает входящий IQueryable и выдает IQueryable / IOrderedQueryable в качестве вывода. С помощью таких функций я могу создавать выражения LINQ с помощью повторно используемого кода, который все еще откладывает запрос до тех пор, пока запрос не будет полностью построен. Здесь, поскольку у меня есть только int (orderID), я не уверен, как заставить его работать.

спасибо

Ответы [ 3 ]

4 голосов
/ 21 апреля 2009

Извините, что отвечаю на мой вопрос, но я нашел хорошее решение. Тем не менее, я думаю, что в зависимости от того, что вы пытаетесь сделать, есть разные способы выделить разные выражения LINQ без оценки IQueryable. Поэтому я надеюсь, что люди поделятся альтернативными решениями.

Мое решение состояло в том, чтобы создать «представление» для факторизованного запроса. Я называю это представлением, потому что оно имеет много общего с представлением SQL (с точки зрения клиента LINQ). В отличие от представления SQL, оно не может быть проиндексировано или иметь постоянные столбцы. Поэтому использование этого представления становится узким местом, поэтому было бы целесообразно использовать реальное представление SQL.

static public class MyDataContextExtension
{
    // The view exposes OrderSummary objects
    public class OrderSummary
    {
        public OrderID { get; set; }
        public string FirstProductListed { get; set; }
    }

    static public IQueryable<OrderSummary> OrderySummaryView(this MyDataContext db)
    {
         return (
              from O in db.Orders
              join OD in db.OrderDetails on O.OrderID equals OD.OrderID into OrderDetails
              let AProductBought = OrderDetails.First().Select(OD => OD.Product.ProductName)
              let TotalCost = OrderDetails.Aggregate(0
              select new OrderSummary()
              {
                  OrderID = OD.OrderID,
                  FirstProductListed = AProductBought.FirstOrDefault()
              };
    }
}

С этим я могу выделить дублированную часть запроса, заменив исходный запрос следующим:

var result = 
from T in db.Transactions
join OS in db.OrderSummaryView() on T.OrderID equals OS.OrderID
select new
{
  TransactionID = T.TransactionID,
  OrderID = T.OrderID,
  FirstProductBought = OS.FirstProductListed
};

Вы можете представить, что добавляются другие столбцы ... Я думаю, что одна интересная вещь заключается в том, что если вы добавляете дополнительные столбцы, но не используете их при окончательном выборе, LINQ фактически не будет запрашивать эти вещи из базы данных. 1009 *

1 голос
/ 15 июня 2012

У нас была такая же проблема. Он не поддерживается "из коробки" и является серьезной проблемой для LOB-приложений. В итоге я написал статью проекта кода о повторном использовании выражений LINQ, включая очень маленькую утилиту LinqExpressionPrjection, которая позволяет повторное использование в проекциях (в том числе в анонимных типах).

Найти статью здесь .

Вы можете получить сборку для повторного использования проекции в виде пакета nuget , а источник включен в CodePlex .

Некоторое время прошло с момента вашего сообщения. Я надеюсь, что это все еще полезно для вас. Если нет, возможно, для других читающих эту ветку.

0 голосов
/ 03 июля 2013

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

X GetSomeX(Expression<Func<Y, X>> map)
{
    return SourceOfYs.Select(map);
}

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

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