Jak liczyć wiersze w ramach EntityFramework bez ładowania zawartości?
Próbuję ustalić, jak hrabia pasujące wiersze w tabeli za pomocą ramki EntityFramework.
Problem polega na tym, że każdy wiersz może mieć wiele megabajtów danych (w polu binarnym). Oczywiście SQL byłby czymś takim:
SELECT COUNT(*) FROM [MyTable] WHERE [fkID] = '1';
Mogę załadować wszystkie wiersze i Następnie znaleźć liczbę z:
var owner = context.MyContainer.Where(t => t.ID == '1');
owner.MyTable.Load();
var count = owner.MyTable.Count();
Ale to jest rażąco nieefektywne. Czy istnieje prostszy sposób?
EDIT: dzięki wszystkim. Przeniosłem DB z prywatny dołączony, więc mogę uruchomić profilowanie; to pomaga, ale powoduje zamieszanie, którego się nie spodziewałem.
A moje prawdziwe dane są nieco głębsze, użyję ciężarówek przewożących palety z przypadków z {5]}przedmiotów -- i nie chcę, aby ciężarówka wyjeżdżała, chyba że jest w niej co najmniej jeden przedmiot {8]}.
Moje próby są pokazane poniżej. Część, której nie rozumiem jest taka, że CASE_2 nigdy nie uzyskuje dostępu do serwera DB (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
I SQL wynikający z przypadku FORMULA_1 jest sp_executesql , ale:
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
[tak naprawdę nie mam ciężarówek, kierowców, palet, skrzyń lub przedmiotów; jak widać z SQL relacje Ciężarówka-paleta i paleta-skrzynia są wiele do wielu -- chociaż nie sądzę, że ma to znaczenie. Moje prawdziwe przedmioty są niematerialne i trudniejsze do opisania, więc zmieniłam nazwy.]
7 answers
Składnia zapytania:
var count = (from o in context.MyContainer
where o.ID == '1'
from t in o.MyTable
select t).Count();
Składnia metody:
var count = context.MyContainer
.Where(o => o.ID == '1')
.SelectMany(o => o.MyTable)
.Count()
Oba generują to samo zapytanie SQL.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-11-03 16:09:58
Myślę, że chcesz coś takiego
var count = context.MyTable.Count(t => t.MyContainer.ID == '1');
(edytowane w celu odzwierciedlenia komentarzy)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-20 22:14:18
Jak rozumiem, wybrana odpowiedź nadal ładuje wszystkie powiązane testy. Według tego bloga msdn jest lepszy sposób.
Konkretnie
using (var context = new UnicornsContext())
var princess = context.Princesses.Find(1);
// Count how many unicorns the princess owns
var unicornHaul = context.Entry(princess)
.Collection(p => p.Unicorns)
.Query()
.Count();
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-01-23 17:04:34
To jest mój kod:
IQueryable<AuctionRecord> records = db.AuctionRecord;
var count = records.Count();
Upewnij się, że zmienna jest zdefiniowana jako IQueryable wtedy gdy użyjesz metody Count (), EF wykona coś w stylu
select count(*) from ...
W przeciwnym razie, jeśli rekordy są zdefiniowane jako IEnumerable, wygenerowany sql zapyta całą tabelę i zliczy zwrócone wiersze.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-24 13:53:03
Cóż, nawet SELECT COUNT(*) FROM Table
będzie dość nieefektywne, szczególnie w przypadku dużych tabel, ponieważ SQL Server naprawdę nie może nic zrobić, ale zrobić pełne skanowanie tabeli (clustered index scan).
Czasami wystarczy znać przybliżoną liczbę wierszy z bazy danych, a w takim przypadku może wystarczyć takie stwierdzenie:
SELECT
SUM(used_page_count) * 8 AS SizeKB,
SUM(row_count) AS [RowCount],
OBJECT_NAME(OBJECT_ID) AS TableName
FROM
sys.dm_db_partition_stats
WHERE
OBJECT_ID = OBJECT_ID('YourTableNameHere')
AND (index_id = 0 OR index_id = 1)
GROUP BY
OBJECT_ID
To sprawdzi dynamiczny widok zarządzania i wyodrębni z niego liczbę wierszy i rozmiar tabeli, biorąc pod uwagę konkretną tabelę. Czyni to sumując w górę wpisów dla sterty (index_id = 0) lub indeksu klastrowego(index_id = 1).
Jest szybki, łatwy w użyciu, ale nie gwarantuje 100% dokładności ani aktualności. Ale w wielu przypadkach jest to " wystarczająco dobre "(i znacznie mniejsze obciążenie serwera). Może tobie też by to pasowało? Oczywiście, aby użyć go w EF, musisz zawinąć to w zapisanym proc lub użyć prostego wywołania "Execute SQL query".Marc
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-21 08:44:16
Użyj ExecuteStoreQuery metoda kontekstu podmiotu. Pozwala to uniknąć pobierania całego zestawu wyników i deserializacji do obiektów, aby wykonać prostą liczbę wierszy.
int count;
using (var db = new MyDatabase()){
string sql = "SELECT COUNT(*) FROM MyTable where FkId = {0}";
object[] myParams = {1};
var cntQuery = db.ExecuteStoreQuery<int>(sql, myParams);
count = cntQuery.First<int>();
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-05-03 18:27:26
Myślę, że to powinno zadziałać...
var query = from m in context.MyTable
where m.MyContainerId == '1' // or what ever the foreign key name is...
select m;
var count = query.Count();
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-20 21:43:34