问题
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