2013-11-07 3 views
2

Моя модель (генерируемой с Entity Framework, иметь в виду, я упростил это для примера) выглядит следующим образом:IReadOnlyCollection часть запроса LINQ

public class Person 
{ 
    public string Name { get; set; } 
    protected virtual ICollection<PersonHouseMapping> PersonHouseMappings { get; set; } 

    public virtual IReadOnlyCollection<House> GetHouses(Func<House, bool> where = null) 
    { 
     var houses = PersonHouseMappings.Select(x => x.House); 

     if (where != null) 
      houses = houses.Where(where); 

     return houses.ToList().AsReadOnly(); 
    } 

    public void AddHouse(House house, DateTime movingDate) 
    { 
     PersonHouseMappings.Add(new PersonHouseMapping 
     { 
      Person = this, 
      House = house, 
      MovingDate = movingDate 
     }); 
    } 
} 

public class House 
{ 
    public int Number { get; set; } 
    protected virtual ICollection<PersonHouseMapping> PersonHouseMappings { get; set; } 
} 

internal class PersonHouseMapping 
{ 
    public virtual Person Person { get; set; } 
    public virtual House House { get; set; } 
    public DateTime MovingDate { get; set; } 
} 

Там в N: M отношения между Person и дома , представленный объектом PersonHouseMapping. Обычно EF представляет это свойство с навигационным свойством, но поскольку PersonHouseMapping имеет дополнительное поле в стороне от PK каждой части сущности отношения, он не может этого сделать.

Отрисовать PersonHouseMapping от пользователей моей библиотеки, поскольку он не так чист, как имеющий свойство навигации, я сделал ICollection защищенным и разоблачил функцию запроса/добавления с помощью методов, которые можно увидеть в классе Person. Я не хочу, чтобы пользователи модифицировали возвращенную коллекцию, потому что они могли подумать, что добавление нового Дома в результат «GetHouses» будет сохранено в БД, что не так. Чтобы заставить их называть «AddHouse», я сделал возвращаемый тип IReadOnlyCollection.

Проблема заключается в том, что, когда я хочу построить запрос для Person, который включает условия относительно своих домов, LINQ не может преобразовать выражение в допустимый Linq to Entities one. Скажем, мы хотим запросить для всех людей, которые владеют дом с номером 1:

dbContext.Persons.Where(p => p.GetHouses(h => h.Number == 1).Any()).ToList(); 

Это не будет работать, и выбросить исключение:

LINQ to Entities does not recognize the method 'System.Collections.Generic.IReadOnlyCollection`1[Namespace.House] GetHouses(System.Func`2[Namespace.House,System.Boolean])' method, and this method cannot be translated into a store expression. 

Который имеет смысл. Но как я могу выполнить то, что хочу, сохраняя способность выполнять эти запросы? Есть что-то вроде IEnumerable, который не может быть создан в List?

EDIT: Я думал, что, вернув IEnumerable вместо IReadOnlyCollection, запрос будет работать (хотя это не решит мою проблему), но это не так. Почему выражение не может быть создано?

EDIT 2: Причина, по которой возврат IEnumerable не будет работать, заключается в том, что проблема не в типе, проблема в том, что вызов метода находится в середине выражения LINQ. Он должен быть непосредственно переведен в магазине запрос, поэтому ни один метод не вызывает :(

Спасибо большого

+0

похоже, нам нужно какое-то пользовательское дерево выражений. –

+0

Я не думаю, что вы можете вызвать произвольный метод в объекте CLR как часть запроса EF, поскольку запрос переводится в SQL, который выполняется в движке базы данных. –

+0

Возможный дубликат [Только для чтения в Entity Framework] (http://stackoverflow.com/questions/11191103/entity-framework-read-only-collections) – ken2k

ответ

0

Единственный способ сделать сбор отображения общественности:

public virtual ICollection<PersonHouseMapping> PersonHouseMappings { get; set; } 

и переписана запрос :

dbContext.Persons.Where(p => p.PersonHouseMappings.Any(m => m.House.Number == 1)).ToList(); 

EF не может разобрать ваш метод и построить часть дерева выражений из него
на самом деле, я не вижу никаких плюсов в вашей. запрос.

+1

Это не соответствует абстрактному PersonHouseMapping от пользователей моей библиотеки , так как это не так чисто, как наличие требования к свойствам навигации OP – ken2k

+0

@ ken2k: при работе с EF (и любым другим OR/M) вы должны понимать, что могут быть какие-либо ограничения.Если кто-то раскрывает EDM как часть публичного API, то он предоставляет те же ограничения пользователям этого API. Если эти ограничения неприемлемы, тогда не делайте этого, сделайте слой модели домена поверх EDM и разоблачите его. – Dennis

+0

Что вы предлагаете, очевидно, решите проблему, это то, что EF дает вам по умолчанию. Но я думаю, что пользователям лучше не создавать каких-либо «картографических» объектов и разбираться с ними; для запроса на чтение, возможно, не так много, но для добавления или удаления гораздо лучше просто вызвать методы. – chuwik

Смежные вопросы