Entity Framework, универсальный шаблон репозитория и странная генерация SQL - PullRequest
4 голосов
/ 15 февраля 2011

Я реализовал общий репозиторий для Entity Framework 4. Вот упрощенная версия, где AllAppContainer - это контекст объекта EF4:

public class Repository<T> where T : class
{
    protected AllAppContainer objectContext;
    protected ObjectSet<T> entitySet;

    public Repository()
    {
        objectContext  = new AllAppContainer();
        entitySet = objectContext.CreateObjectSet<T>();
    }

    public int QueryCount(Func<T, bool> predicate)
    {
        int queryCount = entitySet.Count(predicate);
        return queryCount;
    }
}

Одним из методов является QueryCount (), который я хочу использовать как select Count (*) ... где строка SQL (не возвращая фактические записи).

Прямодушная? Вы могли бы подумать ... Во-первых, давайте сделаем не-репозиторий версию того же самого, выполняя подсчет сущностей Item:

AllAppContainer allAppContainer = new AllAppContainer();
int nonRepCount = allAppContainer.Items.Count(item => item.Id > 0);

SQL Server Profiler говорит, что сгенерированный SQL:

SELECT 
[GroupBy1].[A1] AS [C1]
FROM ( SELECT 
    COUNT(1) AS [A1]
    FROM [dbo].[Items] AS [Extent1]
    WHERE [Extent1].[Id] > 0
)  AS [GroupBy1]

Woo-Hoo! Оценка!

Теперь давайте вызовем то же самое, используя мой репозиторий QueryCount:

Repository<Item> repository = new Repository<Item>();
int repCount = repository.QueryCount(item => item.Id > 0);

Вот сгенерированный SQL:

SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[SmallField] AS [SmallField]
FROM [dbo].[Items] AS [Extent1]

Да, EF возвращает полный набор данных, затем вызывает Count () для него в памяти.

Ради интереса я попытался изменить соответствующую строку в репозитории QueryCount на:

int queryCount = new AllAppContainer().CreateObjectSet<T>().Count(predicate);

и строка без хранилища:

int nonRepCount = allAppContainer1.CreateObjectSet<Item>().Count(item => item.Id > 0);

но сгенерированный SQL для каждого такой же, как и раньше.

Теперь, почему все эти репозитории возвращают все совпадающие записи, а затем рассчитывают, когда это не для не репозитория? И есть ли способ сделать то, что я хочу, через мой общий репозиторий, то есть считать в дБ. Я не могу принять удар производительности в памяти.

1 Ответ

7 голосов
/ 15 февраля 2011

вам нужно использовать Expression<Func<TSource, bool>> predicate для вашего Count, иначе фреймворк использует Enumerable.Count<TSource> Method (IEnumerable<TSource>, Func<TSource, Boolean>), который получает всю коллекцию из БД для возможности вызова для каждого элемента, поэтому ваш метод должен быть:

public int QueryCount(Expression<Func<T, Boolean>> predicate)
{
    int queryCount = entitySet.Count(predicate);
    return queryCount;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...