IReadOnlyCollection是LINQ查询的一部分

时间:2013-11-07 17:27:31

标签: c# linq entity-framework

我的模型(使用实体框架生成,请记住我已将其简化为示例)如下所示:

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; }
}

Person和Houses之间存在N:M关系,由PersonH​​ouseMapping实体表示。通常EF会用导航属性来表示它,但是因为PersonH​​ouseMapping除了关系的每个实体部分的PK之外还有一个额外的字段,所以它不能这样做。

要从我的库的用户那里抽象PersonH​​ouseMapping,因为它不像导航属性那样干净,我已经保护了ICollection并通过Person类中可以看到的方法公开了查询/添加功能。我不希望用户修改返回的集合,因为他们可能会认为在“GetHouses”的结果中添加一个新的House会被保存到DB中,但事实并非如此。为了强制他们调用“AddHouse”,我将返回类型设为IReadOnlyCollection。

问题在于,当我想为Person构建一个包含相对于其Houses的条件的查询时,LINQ无法将表达式转换为有效的Linq到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?

编辑:我认为通过返回IEnumerable而不是IReadOnlyCollection,查询会起作用(虽然它不会解决我的问题),但事实并非如此。为什么不能创建表达式?

编辑2:返回IEnumerable的原因也不起作用的原因是问题不在于类型,问题在于LINQ表达式中间有一个方法调用。它需要直接转换为商店查询,因此没有方法调用:(

非常感谢

1 个答案:

答案 0 :(得分:0)

唯一的方法是将地图集合公开:

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

并重写查询:

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

EF无法解析您的方法并从中构建表达式树的一部分 实际上,我在查询中看不到任何专业人士。