Моя модель (генерируемой с 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. Он должен быть непосредственно переведен в магазине запрос, поэтому ни один метод не вызывает :(
Спасибо большого
похоже, нам нужно какое-то пользовательское дерево выражений. –
Я не думаю, что вы можете вызвать произвольный метод в объекте CLR как часть запроса EF, поскольку запрос переводится в SQL, который выполняется в движке базы данных. –
Возможный дубликат [Только для чтения в Entity Framework] (http://stackoverflow.com/questions/11191103/entity-framework-read-only-collections) – ken2k