Поддерживает ли LINQ to SQL или любой другой ORM с поддержкой LINQ фильтрацию ассоциаций? - PullRequest
1 голос
/ 20 июля 2011

По-видимому, согласно this вы не можете запросить множество отношений, не загружая всю коллекцию.Другими словами, это LINQ to Objects вместо LINQ to Entities запроса.

Например:

Category category = db.Categories.Find(1);
var productsThatStartWithA = category.Products.Where(p => p.Name.StartsWith("A")).ToList();

Приведенный выше запрос загружает все товары в этой категории, а затем применяется фильтр.

Вопрос № 1

Это правильно?Я не могу поверить, насколько это глупо.

Вопрос № 2

Может ли LINQ to SQL или любой другой LINQ включен ORM справиться с этим так, как этодолжен работать?

Альтернативы, представленные в связанном вопросе и Slauma's , являются обходными, а не решениями.Они требуют ссылки на объект контекста, который недоступен, если вы пишете код, отделенный от Entity Framework API, и / или ваш код является объектно-ориентированным, например:

public class Category { 

   public IEnumerable<Product> GetProductsThatStartWithA() {
      return this.Products.Where(p => p.Name.StartsWith("A")).ToList()
   }
}

Ответы [ 3 ]

2 голосов
/ 21 июля 2011

Печально то, что Linq to SQL на самом деле обеспечивает гораздо лучшую поддержку для этого (с DataLoadOptions.AssociateWith, но это не совсем то, что вам нужно), тогда как Linq для сущностей / EF предоставляет только то, что вы называете обходным решением - даже в отношении реализация и существующая разница между IEnumerable и IQueryable это выглядит как правильное решение.

То, что вы хотите, потребует, чтобы коллекция выставляла IQueryable и вызывала внутренний код, показанный @Slauma, если коллекция не загружена = linq-to-entity или общие linq-to-objects в загруженной коллекции. Я не уверен, что это может сработать, но вы можете поиграть с ним. Здесь у вас есть несколько отправных точек:

Btw. Вы должны отключить отложенную загрузку EF, иначе это будет иметь приоритет.

1 голос
/ 20 июля 2011

Неправильно, что запросы, подобные запросам в вашем примере, возможны только в памяти (LINQ to Objects).

Вы можете добиться отфильтрованной загрузки коллекции с двумя обращениями в БД - см. Параметр 1 вОтвет Ладислава на связанный вопрос.Чтобы перевести это на ваш конкретный пример, это будет выглядеть так:

Category category = db.Categories.Find(1);
var productsThatStartWithA = db.Entry(category)
    .Collection(c => c.Products)
    .Query()
    .Where(p => p.Name.StartsWith("A"))
    .ToList();

Это не загружает полную коллекцию Products, а только отфильтрованный набор.Это LINQ to Entities, а не LINQ to Objects, и он работает с ленивой загрузкой и без нее.

Более того, вы можете достичь того же результата с помощью одного обращения и одного запроса, проецируя в анонимный тип:

var result = db.Categories.Where(c => c.Id == 1)
    .Select(c => new
    {
        Category = c,
        ProductsStartingWithA = c.Products.Where(p => p.Name.StartsWith("A"))
    })
    .SingleOrDefault();

Здесь вы найдете свою категорию и коллекцию отфильтрованных продуктов в result.Category и result.ProductsStartingWithA.

0 голосов
/ 20 июля 2011

Вам необходимо запомнить разницу между LINQ to Entities и LINQ to Objects.

A .Where() в LINQ to Entities будет преобразовано в SQL. A .Where в LINQ to Objects не будет.

Вы можете действительно легко использовать SQL, чтобы ограничить список объектов с помощью LINQ to Entities. Вы также можете очень легко избежать тихой и невидимой генерации запросов к БД с помощью LINQ to Objects.

Короче говоря, разница существует именно потому, что, как вы подразумеваете, иногда полезно использовать SQL (но не каждый раз!). Если вам это кажется «глупым», я бы посоветовал вам потратить некоторое время на то, чтобы понять, как все работает, и узнать, как они на самом деле работают. имеет смысл , если ваши ожидания совпадают с реализацией.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...