2010-09-30 4 views
2

J'ai des problèmes avec mon application linq.Problème de requête Linq (trop de requête ado.net)

J'ai commandes, OrderChangeLog et OrderItems tables. Dans une requête, je veux charger des commandes et des tables dépendantes. J'utilise Linq.

return from p in _db.dbOrders 
select new Order 
{ 
ID = p.ID, 
OrderStatusChangelog = new List<OrderStatusChangelog>(GetOrderStatusChangelog().Where(x => x.OrderID == p.ID)), 
Items = new List<OrderItem>(GetOrderItems(p.ID)), }; 

Dans cette variante, il prend trop de demandes de ADO.NET (voir image1) image1 full size image1

Mais. Si je commente

Items = new List<OrderItem>(GetOrderItems(p.ID)) 

Résultat parfait (image2 full size) image2

Pourquoi un travail rejoindre ainsi?

P.S. Mon T-SQL (généré par LINQ):

{SELECT [t0].[ID], [t0].[UserID], [t0].[DateOrder] AS [DateCreated], [t0].[ControlGUID] AS [Guid], [t0].[StatusID], [t1].[ID] AS [ID2], [t1].[OrderID], [t1].[StatusID] AS [OrderStatusID], [t1].[Comment] AS [StatusMessage], [t1].[UserID] AS [UserID2], [t1].[Date], [t2].[FullName] AS [UserName], (
SELECT COUNT(*) 
FROM [dbo].[dbOrderStatusChangelog] AS [t3] 
INNER JOIN [dbo].[dbUsers] AS [t4] ON [t4].[ID] = [t3].[UserID] 
WHERE [t3].[OrderID] = [t0].[ID] 
) AS [value], [t0].[ShippingFLP], [t0].[ShippingAddress] AS [ShippingAddressContent], [t0].[ShippingRegionID], [t0].[ShippingCity], [t0].[ShippingZIPCode], [t0].[ShippingPhone], [t0].[ShippingMetroID], [t0].[PaymentFLP], [t0].[PaymentAddress] AS [PaymentAddressContent], [t0].[PaymentRegionID], [t0].[PaymentCity], [t0].[PaymentZIPCode], [t0].[PaymentPhone], [t0].[TrackingNumber], [t0].[DateShipped], [t0].[ShippingCost] AS [Rate], [t0].[ShippingName] AS [Name], [t0].[ShippingTypeID], [t0].[PaymentName] AS [Name2], [t0].[PaymentTypeID], [t0].[SourceID], [t0].[CustomerComment], [t0].[CustomerEmail], [t0].[CustomerFLP], [t0].[DiscountAmount] AS [discountAmount], [t0].[DiscountReason] AS [discountReason], [t0].[Amount] 
FROM [dbo].[dbOrders] AS [t0] 
LEFT OUTER JOIN ([dbo].[dbOrderStatusChangelog] AS [t1] 
    INNER JOIN [dbo].[dbUsers] AS [t2] ON [t2].[ID] = [t1].[UserID]) ON [t1].[OrderID] = [t0].[ID] 
WHERE (CONVERT(Int,[t0].[StatusID])) IN (@p0, @p1, @p2) 
ORDER BY [t0].[ID] DESC, [t1].[ID], [t2].[ID]} 

Tableau diagramme tables

UPD1

private IQueryable<OrderItem> GetOrderItems(int orderID) 
    { 
     return from p in _db.dbOrderItems 
       where p.OrderID == orderID 
       select new OrderItem 
          { 
           ID = p.ID, 
           ItemPrice = p.Price, 
           OrderID = p.OrderID, 
           Quantity = p.Quantity, 
           Product = new Product 
              { 
               ID = p.ProductID, 
               Name = p.ProductName, 
               Brand = new Brand { Name = p.dbProduct.dbBrand.Name } 
              } 
          }; 
    } 


    private IQueryable<OrderStatusChangelog> GetOrderStatusChangelog() 
    { 
     return from p in _db.dbOrderStatusChangelogs 
       select new OrderStatusChangelog 
          { 
           Date = p.Date, 
           ID = p.ID, 
           OrderID = p.OrderID, 
           OrderStatusID = p.StatusID, 
           StatusMessage = p.Comment, 
           UserID = p.UserID, 
           UserName = p.dbUser.FullName 
          }; 
    } 
+1

Je ne comprends pas pourquoi les images SO ne sont pas cliquables ... vous devez les faire glisser dans la barre d'adresse pour l'amour de Dieu ...: D – Letterman

+0

Quel est le code de 'GetOrderItems' et' GetOrderStatusChangelog'? .. Listes force l'énumération, vous pouvez tirer parti de 'IQueryable' pour compenser la charge à la demande. –

Répondre

1
Items = new List... 

Cela entraînera une énumération des éléments que vous interrogez, forcer l'appel à la base de données pour chaque liste créée (et éléments copiés).

Vous pouvez différer l'énumération et l'appel au consommateur et leur demander de convertir les éléments en liste, ou vous pouvez créer une méthode qui créera une liste pour eux à la demande ou changer leur façon d'interagir en définissant votre définition un IEnumerable et juste retourner le IQueryable. La vraie question est, est-il nécessaire pour chaque élément d'être une liste et d'être entièrement rempli sur la requête principale ou pouvez-vous retarder l'exécution jusqu'à ce que les données soient traitées?

+0

Une liste _IS_ IEnumerable - Je pense que vous vouliez dire IQueryable? – Basic

+0

Oui, je peux vous retarder l'exécution jusqu'à ce que les données soient activées. Mais GetOrderItems et GetOrderStatusChangelog ressemblance. Et fonctionne mal seulement GetOrderItems(); GetOrderStatusChangelog - fonctionne bien – Dmitriy

+0

@Basiclife Non, je ne l'ai pas fait, 'IQueryable' est' IEnumerable' aussi, mais si la signature de 'Items' a été changée de' List' à 'IEnumerable' il pourrait se débarrasser des appels au Constructeur de liste et renvoie simplement 'GetOrderItems' etc. qui serait différer le chargement à l'énumération réelle de l'ensemble. –