У меня есть несколько наборов данных, которые получены из контекста кода Entity Framework (SQL CE). Есть графический интерфейс, который отображает количество записей в каждом наборе запросов, и при изменении некоторого установленного условия (например, даты), все наборы должны пересчитать свое «счетное» значение.
Хотя запросы каждого набора в чем-то немного отличаются, большинство из них тем или иным образом имеют общие условия. Простой пример:
RelevantCustomers = People.Where(P=>P.Transactions.Where(T=>T.Date>SelectedDate).Count>0 && P.Type= = "Customer")
RelevantSuppliers = People.Where(P=>P.Transactions.Where(T=>T.Date>SelectedDate).Count>0 && P.Type= = "Supplier")
Дело в том, что этих требовательных запросов достаточно, что каждый раз, когда пользователь изменяет какое-либо условие (например, SelectedDate), требуется очень много времени, чтобы пересчитать количество записей в каждом наборе.
Я понимаю, что отчасти причина этого заключается в необходимости запрашивать, например, транзакции каждый раз, чтобы проверить, что на самом деле является условием такой же как для RelevantCustomers, так и для RelevantSuppliers.
Итак, мой вопрос в том, что, учитывая, что эти наборы имеют общие «базовые условия», которые зависят от одних и тех же наборов данных, есть ли более эффективный способ вычисления этих наборов?
Я думал что-то с такими настраиваемыми универсальными классами:
QueryGroup<People>(P=>P.Transactions.Where(T=>T.Date>SelectedDate).Count>0)
{
new Query<People>("Customers", P=>P.Type= = "Customer"),
new Query<People>("Suppliers", P=>P.Type= = "Supplier")
}
Я могу легко структурировать это, но я обнаружил, что это практически не влияет на эффективность, поскольку все равно необходимо повторять «общее условие» для каждого набора.
Я также пробовал сначала вытащить данные базового состояния как статический «ToList ()», но это вызывает проблемы при работе с объектами навигации (т. Е. People.Addresses не загружаются).
Есть ли какой-то метод, о котором я здесь не знаю с точки зрения эффективности?
Заранее спасибо!


Попробуйте что-то вроде этого: объедините «похожие» значения в меньшее количество запросов, а затем разделите результаты. Кроме того, для проверки наличия используйте Any(), а не Count(). Ваша обновленная попытка идет частично, но все равно приведет к двукратному обращению к базе данных. Кроме того, при запросе это помогает убедиться, что вы запрашиваете индексированные поля, и эти индексы будут более эффективными с числовыми идентификаторами, а не со строками. (То есть TypeID 1 против 2 для «Заказчик» или «Поставщик»). Нормализованные значения лучше подходят для индексации и приводят к меньшим записям за счет дополнительных подробных запросов.
var types = new string[] {"Customer", "Supplier"};
var people = People.Where(p => types.Contains(p.Type)
&& p.Transactions.Any(t => t.Date > selectedDate)).ToList();
var relevantCustomers = people.Where(p => p.Type == "Customer").ToList();
var relevantSuppliers = people.Where(p => p.Type == "Supplier").ToList();
Это приводит к одному обращению к базе данных, и Any должен быть более производительным, чем выбор всего счетчика. Мы разделяем клиентов и поставщиков постфактум из набора в памяти. Предостережение здесь в том, что любая попытка получить доступ к деталям, таким как транзакции и т. д., По клиентам и поставщикам приведет к ленивым обращениям, поскольку мы не стремились их загружать. Если вам нужны целые графы сущностей, обязательно укажите соответствующие детали .Include () или будьте более избирательны в отношении данных, извлеченных из первого запроса. Т.е. выберите анонимные типы с применимыми деталями, а не только сущность.
Вау! Этот ответ был более подробным / полезным, на что я мог надеяться! Большое спасибо!