C# 建立EF查询时如何将WHERE条件应用于EF.Include()

C# 建立EF查询时如何将WHERE条件应用于EF.Include(),c#,.net,entity-framework,C#,.net,Entity Framework,我有以下两门课: public class Rule { public int Id { get; set; } public string RuleValue { get; set; } public bool IsActive { get; set; } public SharedRuleType RuleType { get; set; } public List<Exclusion> Exclusions { get; set; } }

我有以下两门课:

public class Rule
{
    public int Id { get; set; }
    public string RuleValue { get; set; }
    public bool IsActive { get; set; }
    public SharedRuleType RuleType { get; set; }
    public List<Exclusion> Exclusions { get; set; }
}

public class Exclusion
{
    public int Id { get; set; }
    public int InstanceId { get; set; }
    public int SiteId { get; set; }
    [ForeignKey( "RuleId" )]
    public int RuleId { get; set; }
    public Rule Rule { get; set; }
}
我尝试在
.Include()
中应用.Where,试图只包含相关的
排除项
(基于
实例ID
),但发现您不能这样做。我四处寻找,发现了一些人们使用匿名类型的例子,但在我这里一块一块地构建查询时,我无法实现这一点


所以,我不知道如何才能做到这一点,因为我真的不想为每个
规则
返回'every'
排除
,而我不需要返回每个
排除

编辑根据您的评论,您需要执行使表左连接的请求

这是您的新方法的变体

public class RuleModel
{
    public Rule Rule { get; set; }
    public IEnumerable<Exclusion> Exclusions { get; set; }
}   

public async Task<List<RuleModel>> GetRules(int instanceId, SharedRuleType ruleType, string searchTerm)
{
    using ( var context = new MyDbContext() )
    {
        var query = context.Set<Rule>()
            .Where( r => r.IsActive );

        if ( !string.IsNullOrEmpty( searchTerm ) )
        {
            query = query.Where( r => r.RuleValue.Contains( searchTerm ) );
        }

        if ( ruleType != SharedRuleType.None )
        {
            query = query.Where( r => r.RuleType == ruleType );
        }

        // That statement do LEFT JOIN like:
        // FROM  Rules
        // LEFT OUTER JOIN Exclusions ON ([Rules].[Id] = [Exclusions].[RuleId]) AND ([Exclusions].[InstanceId] = @instanceId)
        var ruleExclusionQuery = query.Select(rule => new RuleModel { Rule = rule, Exclusions = rule.Exclusions.Where(e => e.InstanceId == instanceId) });
        var ruleList = await ruleExclusionQuery.ToListAsync();
    }
}

不再需要了。

Include方法无法像您尝试的那样使用筛选器

解决方案#1

免责声明:我是项目的所有者

EF+查询IncludeFilter功能允许筛选相关实体

public async Task<List<Rule>> GetRules(int instanceId, SharedRuleType ruleType, string searchTerm)
{
    using ( var context = new MyDbContext() )
    {
        var query = context.Set<Rule>()
            .IncludeFilter( r => r.Exclusions.Where(x => x.InstanceId == instanceId))
            .Where( r => r.IsActive );

        // ... code ...
编辑:回答子问题#2

如何对规则执行跳过、执行、排序

你和平时一样

return  (await query.Take(15)
                    .Skip(5)
                    .OrderBy(x => x.RuleId)
                    .Select(x => new { Rule = x,
                                            Exclusions = x.Exclusions.Where(e => e.InstanceId == instanceId)
                                })
     .ToListAsync())
     .Select(x => x.Rule)
     .ToList();
条件包含
尚未由EF团队实施 这仍然是EF团队的工作项,您可以投票

请注意,当前无法筛选加载的相关实体。Include将始终引入所有相关实体。

如果要筛选include语句,需要使用EF上的投影

using ( var context = new MyDbContext() )
{

    Expression<Func<Rules, bool>> whereCondition;

    if (!string.IsNullOrEmpty( searchTerm ) )
    {
        whereCondition= x.RuleValue.Contains(searchTerm));
    }

    var query = context.Rules
                       .Where(whereCondition)
                       .Select(x=> new 
                       {
                         rules = x,
                         exclustions = x.Exclusions.Where(secondCondition).ToList()
                       }.ToList();
}

有时候执行正确的SQL更容易。@VinodKumar不,还没有。我认为Vitaliy下面的解决方案不会起作用,因为它不会返回“全部”规则,它会根据排除情况过滤掉一些规则。有一次我在看这个。我模模糊糊地记得,我发现这是不可能的,但无法引用一个来源。也许最好通过SQL或单独的查询加载数据。在我的例子中,为满足条件的相关实体编写另一个查询是可以的。但是这不会过滤掉我的一些规则吗(只返回与实例匹配的排除规则)?我需要“所有”规则,不管它们是否有排除(以及它们是什么排除)。它只是需要过滤的包含的排除项(如果有)。@marcusstarnes我更新了代码。请检查它是否适合您。感谢您提供可能的解决方案。有一个问题,关于解决方案#2,我将如何将.Skip、.Take和.OrderBy合并到查询中,以便在一次到数据库的过程中执行过滤,因为事实证明我需要它。另外,我将如何使用wait/Async实现解决方案#2?您希望在哪个实体(规则或排除)上执行Skip、Take、OrderBy?规则。对于返回的每个规则,我总是希望“全部”过滤排除,但我可能一次只请求10条规则(为跳过和执行提供偏移量和限制)。如果这10条规则中的一条碰巧有50条过滤排除规则,我希望所有50条排除规则都适用。我还将传递一些东西(枚举)来标识要应用的请求排序顺序。谢谢,这正是我所需要的。
public async Task<List<Rule>> GetRules(int instanceId, SharedRuleType ruleType, string searchTerm)
{
    using ( var context = new MyDbContext() )
    {
        var query = context.Set<Rule>()
            .Where( r => r.IsActive );

        if ( !string.IsNullOrEmpty( searchTerm ) )
        {
            query = query.Where( r => r.RuleValue.Contains( searchTerm ) );
        }

        if ( ruleType != SharedRuleType.None )
        {
            query = query.Where( r => r.RuleType == ruleType );
        }


        // ToListAsync has been removed to make the example easier to understand
        return  query.Select(x => new { Rule = x,
                                        Exclusions = x.Exclusions.Where(e => e.InstanceId == instanceId)
                    })
             .ToList()
             .Select(x => x.Rule)
             .ToList();
    }
}
return  (await query.Select(x => new { Rule = x,
                                Exclusions = x.Exclusions.Where(e => e.InstanceId == instanceId)
            })
     .ToListAsync())
     .Select(x => x.Rule)
     .ToList();
return  (await query.Take(15)
                    .Skip(5)
                    .OrderBy(x => x.RuleId)
                    .Select(x => new { Rule = x,
                                            Exclusions = x.Exclusions.Where(e => e.InstanceId == instanceId)
                                })
     .ToListAsync())
     .Select(x => x.Rule)
     .ToList();
using ( var context = new MyDbContext() )
{

    Expression<Func<Rules, bool>> whereCondition;

    if (!string.IsNullOrEmpty( searchTerm ) )
    {
        whereCondition= x.RuleValue.Contains(searchTerm));
    }

    var query = context.Rules
                       .Where(whereCondition)
                       .Select(x=> new 
                       {
                         rules = x,
                         exclustions = x.Exclusions.Where(secondCondition).ToList()
                       }.ToList();
}
    if ( !string.IsNullOrEmpty( searchTerm ) )
    {
        whereCondition= x.RuleValue.Contains( searchTerm);
    }

    if ( ruleType != SharedRuleType.None )
    {
        whereCondition= x.RuleType ==ruleType;
    }
    //Ugly work around is 
    if ( !string.IsNullOrEmpty( searchTerm ) && ruleType != SharedRuleType.None)
    {
        whereCondition= x.RuleValue.Contains( searchTerm) && x.RuleType ==ruleType;
    }