EF Lambda包含导航属性

时间:2020-02-07 16:53:19

标签: c# entity-framework linq lambda

我有一个名为Filter的对象,它具有以下属性:

    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Type> Types{ get; set; }
    public virtual ICollection<Step> Steps { get; set; }
    public virtual ICollection<Flow> Flows { get; set; }
    public virtual ICollection<Room> Rooms { get; set; }

当我从数据库中选择过滤器列表时,我不知道如何包括集合(类型,步骤,流程,房间)。我的代码如下:

var filters = (
            from filter in dbContext.DbSet<Filter>()
            let rooms = (
                from r in dbContext.DbSet<Room>()
                select r
                )
            let eventTypes = (
                from t in dbContext.DbSet<Type>()
                select t
                )
            let processFlows = (
                from f in dbContext.DbSet<Flow>()
                select f
                )
            let processFlowSteps = (
                from s in dbContext.DbSet<Step>()
                select s
                )
            select filter
            ).ToList();

返回了我的Filter集合,但是里面的集合为空。您能告诉我如何实现吗?

Ps:由于性能问题,我不想使用Include,我不喜欢Entity Framework如何生成查询,并且我想这样做。

3 个答案:

答案 0 :(得分:1)

您需要使用Include扩展方法:

var filters=dbContext.DbSet<Filter>()
                     .Include(f=>f.Types)
                     .Include(f=>f.Steps)
                     .Include(f=>f.Flows)
                     .Include(f=>f.Rooms)
                     .ToList()

更新

@MrSilent,Include扩展方法是专门为加载相关实体而设计的,我认为您拥有的另一种选择是执行raw sql,但是您做的方式却并非如此要进行一次,您有四个往返数据库的往返时间,而您需要使用join来获取相关实体,Include会为您生成这些连接,而这只是一次往返。

例如,这是我想您可以使用的另一种方式,但是再次违反了使用EF的目的,模型的思想还在于表示表之间的关系,而不仅仅是表示它们之间的关系。

var query= from f in context.DbSet<Filter>()
           from s in f.Steps
           from r in f.Rooms
           from t in f.Types
           from fl in f.Flows
           select new {f, s, r, t, fl};

答案 1 :(得分:1)

您的方法有效,您只是在做错了。

要包括导航属性,您要做的只是一个子选择(使用linq),例如:

var filters = (from filter in dbContext.DbSet<Filter>()
                select new Filter
                {
                    filter.Id,
                    filter.Name,
                    Rooms = (from r in dbContext.DbSet<Room>()
                            where r.FilterId == filter.Id
                            select r).ToList()
                }).ToList();

请记住,直到您调用返回方法(ToList,Any,FirstOrDefault等),EF才会执行查询。这样,它不会执行不希望通过不使用Include()避免的丑陋查询,而只会触发两个查询并在所需对象中正确分配值。

答案 2 :(得分:0)

您可以使用延迟加载,方法如下:

您首先需要获取Include属性,使其成为虚拟属性,然后获取一个受保护的访问类型的空构造函数以很好地完成工作。

public virtual ICollection<Type> Types{ get; set; }
public virtual ICollection<Step> Steps { get; set; }
public virtual ICollection<Flow> Flows { get; set; }
public virtual ICollection<Room> Rooms { get; set; }

还有

 //FOR EF !
 protected Filter() { }

我认为此解决方案可以解决您的问题。

相关问题