J'essaie de déterminer comment compter les lignes correspondantes d'une table en utilisant l'EntityFramework.
Le problème est que chaque ligne peut contenir plusieurs mégaoctets de données (dans un champ binaire). Bien sûr, le SQL serait quelque chose comme ceci :
SELECT COUNT(*) FROM [MyTable] WHERE [fkID] = '1';
Je pourrais charger toutes les rangées et puis trouver le comte avec :
var owner = context.MyContainer.Where(t => t.ID == '1');
owner.MyTable.Load();
var count = owner.MyTable.Count();
Mais c'est tout à fait inefficace. Existe-t-il un moyen plus simple ?
EDIT : Merci à tous. J'ai déplacé la base de données d'une pièce jointe privée pour pouvoir exécuter le profilage ; cela aide mais provoque des confusions auxquelles je ne m'attendais pas.
Et mes données réelles sont un peu plus profondes, je vais utiliser Camions portant Palettes de Cas de Articles -- et je ne veux pas que le Camion de partir à moins qu'il y ait au moins un Article en elle.
Mes tentatives sont présentées ci-dessous. La partie que je ne comprends pas est que CASE_2 n'accède jamais au serveur de base de données (MSSQL).
var truck = context.Truck.FirstOrDefault(t => (t.ID == truckID));
if (truck == null)
return "Invalid Truck ID: " + truckID;
var dlist = from t in ve.Truck
where t.ID == truckID
select t.Driver;
if (dlist.Count() == 0)
return "No Driver for this Truck";
var plist = from t in ve.Truck where t.ID == truckID
from r in t.Pallet select r;
if (plist.Count() == 0)
return "No Pallets are in this Truck";
#if CASE_1
/// This works fine (using 'plist'):
var list1 = from r in plist
from c in r.Case
from i in c.Item
select i;
if (list1.Count() == 0)
return "No Items are in the Truck";
#endif
#if CASE_2
/// This never executes any SQL on the server.
var list2 = from r in truck.Pallet
from c in r.Case
from i in c.Item
select i;
bool ok = (list.Count() > 0);
if (!ok)
return "No Items are in the Truck";
#endif
#if CASE_3
/// Forced loading also works, as stated in the OP...
bool ok = false;
foreach (var pallet in truck.Pallet) {
pallet.Case.Load();
foreach (var kase in pallet.Case) {
kase.Item.Load();
var item = kase.Item.FirstOrDefault();
if (item != null) {
ok = true;
break;
}
}
if (ok) break;
}
if (!ok)
return "No Items are in the Truck";
#endif
Et le SQL résultant de CASE_1 est acheminé par le biais de sp_executesql mais :
SELECT [Project1].[C1] AS [C1]
FROM ( SELECT cast(1 as bit) AS X ) AS [SingleRowTable1]
LEFT OUTER JOIN (SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(cast(1 as bit)) AS [A1]
FROM [dbo].[PalletTruckMap] AS [Extent1]
INNER JOIN [dbo].[PalletCaseMap] AS [Extent2] ON [Extent1].[PalletID] = [Extent2].[PalletID]
INNER JOIN [dbo].[Item] AS [Extent3] ON [Extent2].[CaseID] = [Extent3].[CaseID]
WHERE [Extent1].[TruckID] = '....'
) AS [GroupBy1] ) AS [Project1] ON 1 = 1
[ Je n'ai pas vraiment de camions, de chauffeurs, de palettes, de caisses ou d'articles ; comme vous pouvez le voir dans le SQL, les relations entre les camions et les palettes et entre les palettes et les caisses sont de plusieurs à plusieurs, bien que je ne pense pas que cela soit important. Mes vrais objets sont intangibles et plus difficiles à décrire, c'est pourquoi j'ai changé les noms. ]