Aggregating multiple queries into one with EF like this?

ぐ巨炮叔叔 提交于 2020-01-04 02:30:54

问题


I am using EF 4.0 POCO in my application. Are there any downsides to retrieving information like this?

Given a customerId and a productId, I would like to apply some business rules that require me to fetch lots teeny pieces of information from the database requiring multiple queries. Instead, I could write one query like so:

var customerId = 1;
var productId = 1;

var aggregateQuery = 
    from entry in Customers.Take(0).DefaultIfEmpty()
    select new
    {
        numberOfOrders = SalesOrderHeaders.Where (header => header.CustomerID == customerId).Count(),
        canSellProduct = Products.Where(product => product.ProductID == productId && product.SellEndDate > DateTime.Now).Count () > 0

        //more infromation of this sort, required to enforce business rules
    };

var informationPacket = aggregateQuery.First();

The Customers.Take(0).DefaultIfEmpty() just gives a way to start the query and Customers, SalesOrderHeaders and Products are EF ObjectQuery instances from the context (This example if from LinqPad). This results in the following SQL:

-- Region Parameters
DECLARE @p0 Int = 1
DECLARE @p1 Int = 1
DECLARE @p2 DateTime = '2012-04-04 21:02:20.798'
DECLARE @p3 Int = 0
-- EndRegion
SELECT TOP (1) [t6].[value] AS [numberOfOrders], [t6].[value2] AS [canSellProduct]
FROM (
    SELECT (
        SELECT COUNT(*)
        FROM [Sales].[SalesOrderHeader] AS [t3]
        WHERE [t3].[CustomerID] = @p0
        ) AS [value], 
        (CASE 
            WHEN ((
                SELECT COUNT(*)
                FROM [Production].[Product] AS [t5]
                WHERE ([t5].[ProductID] = @p1) AND ([t5].[SellEndDate] > @p2)
                )) > @p3 THEN 1
            WHEN NOT (((
                SELECT COUNT(*)
                FROM [Production].[Product] AS [t5]
                WHERE ([t5].[ProductID] = @p1) AND ([t5].[SellEndDate] > @p2)
                )) > @p3) THEN 0
            ELSE NULL
         END) AS [value2]
    FROM (
        SELECT NULL AS [EMPTY]
        ) AS [t0]
    OUTER APPLY (
        SELECT TOP (0) NULL AS [EMPTY]
        FROM [Sales].[Customer] AS [t1]
        ) AS [t2]
    ) AS [t6]

回答1:


I lean to using separate queries for three reasons:

  • Isolation: Separate queries are much clearer and better maintainable: with one monolith query, each change potentially has many side-effects. It is easier to apply business rules to small, isolated pieces of code.
  • Efficiency: You might end up composing a query that is far less inefficient than separate queries because it gets impossible to find a good execution plan, this may even outweigh the cost of more database round-trips (but that is to be benchmarked).
  • Locked-in: It may work for a while, until requirements change in a way that one big query does not work anymore: may require a disproportional lot of refactoring.

Plus a bit of gut feeling: needing some trick (Take(0)) is often indicative of bad design (or maybe you're just f** brilliant, but in my case it's usually the former).

However, I see the potential advantages of course. As said, it may turn out to perform better because of less db roundtrips. And it is quite comfortable to use one select new to compose one data transfer object as opposed to knitting it together from the separate bits.

So, not a clear cut verdict. Personally I like to keep things simple and deal with performance when it really is an issue.



来源:https://stackoverflow.com/questions/10021795/aggregating-multiple-queries-into-one-with-ef-like-this

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!