如何通过字典筛选子表

14 浏览
0 Comments

如何通过字典筛选子表

我有一个问题要问你们!!!假设我有两个表,一个是父表,另一个是子表。我想通过从子对象发送数据来过滤父表。子表包含4列,如下所示:

{Id, RuleId, RuleKey, RuleValue}

我发送一个字典作为请求,其中包含子对象的2个列(RuleKey,RuleValue)的值。我想返回包含我发送的RuleKey和RuleValue的父对象。

// Key是子表的列名,value是相应的值
var dictionary = new Dictionary()
{
    {"RuleKey", "RuleValue"},
    {"RuleKey1", "RuleValue1"}
}

这是我尝试的方法,但显然不起作用,仍然会出现语法错误。

关于这个问题有两个问题:

1-) 我应该如何做到这一点(重要的)

2-) 如果我在内存中执行这个操作,会有任何错误吗?如果我记得没错的话,EFCore不会将LINQ转换为SQL脚本,因为内存问题。

var rules = _ruleContext.Rules.AsQueryable();
rules = rules.Where(u => u.Criteria.Where(k => dictionary.Keys.Contains(k.Key) && dictionary.Values.Contains(k.Value)));

public class Rule : Entity
{
    public string RuleName { get; set; }
    public string Expression { get; set; }
    public ICollection Criteria { get; set; }
}
public class Criteria : Entity
{
    public int RuleId { get; set; }
    public string Name { get; set; }
    public string Key { get; set; }
    public string Operator { get; set; }
    public string Value { get; set; }
    public Rule Rule { get; set; }
}

0
0 Comments

如何通过字典过滤子表

问题出现的原因:

用户希望通过使用字典来过滤子表,但不清楚如何实现。

解决方法:

可以使用函数FilterByItems来实现字典过滤子表的功能。下面是具体的解决方法。

首先,创建一个字典对象,其中包含要用于过滤的规则。例如:

var dictionary = new Dictionary()
{
    {"RuleKey", "RuleValue"},
    {"RuleKey1", "RuleValue1"}
};

然后,使用FilterByItems函数对子表进行过滤。在过滤过程中,使用lambda表达式指定过滤条件。例如:

var matched = _ruleContext.Criterias
    .FilterByItems(dictionary, (c, kv) => c.Key == kv.Key && c.Value == kv.Value, true)
    .GroupBy(c => c.RuleId)
    .Where(g => g.Count() == dictionary.Count)
    .Select(g => new
    {
        RuleId = g.Key,
    });

接下来,将过滤后的结果与主表进行关联,并选择需要的字段。例如:

var rules =
    from r in _ruleContext.Rules
    join m in matched on r.Id equals m.RuleId
    select r;

最后,将结果转换为数组或其他需要的形式。例如:

var result = rules.ToArray();

通过以上步骤,就可以实现通过字典过滤子表的功能了。

文章结束。

0
0 Comments

问题的出现原因:

这个问题的出现是因为需要根据字典来过滤子表。根据代码中的描述,需要匹配字典中的键值对,而不是只匹配键或值。目前的代码中,无法实现只匹配键值对的需求。

问题的解决方法:

为了解决这个问题,可以创建一个临时表来存储字典中的键值对,然后使用原始的SQL语句来将子表与临时表进行连接。具体的解决方法如下:

// 为了使用临时表,需要保证连接在表创建语句之后保持打开状态
context.Database.OpenConnection();
try
{
    context.Database.ExecuteSqlRaw("CREATE TABLE #RequiredCriteria ([Value] nvarchar(100), [Key] nvarchar(100))");
    // 如果需要处理大量的条件,这可能会成为瓶颈...
    foreach (var criteria in dictionary)
    {
        context.Database.ExecuteSqlInterpolated($"INSERT INTO #RequiredCriteria ([Value], [Key]) VALUES ({criteria.Key}, {criteria.Value})");
    }
    // 这个查询使用原始的SQL语句创建Rule对象,并进行所需的参数连接
    var matched = context.Rules.FromSqlRaw(
        @"SELECT * FROM Rules 
        WHERE Id IN (
            SELECT DISTINCT RuleId 
            FROM Criteria C 
                INNER JOIN #RequiredCriteria RC 
                    ON C.[Key] = RC.[Key] AND C.[Value] = RC.[Value])")
        .ToList();
    context.Database.ExecuteSqlRaw("DROP TABLE #RequiredCriteria");
}
finally
{
    context.Database.CloseConnection();
}

第二个解决方法中添加了一个GROUP BY和HAVING COUNT(RuleId) = {dictionary.Count}的语句,以确保匹配的规则具有与请求的条件相同的不同条件数量。这样,如果请求中重复了相同的条件键和值,也不会造成影响。

如果Criteria表的数据量很大,建议在Key和Value列上建立索引,否则每次查询都会对整个表进行聚集索引扫描。

正确的解决方法是通过原始的SQL语句来实现的。但是可以省略Distinct,因为字典中的键是唯一的。

0