C# 使用IEnumerable中的属性值从DbSet获取所有实体

C# 使用IEnumerable中的属性值从DbSet获取所有实体,c#,mysql,entity-framework,linq,entity-framework-core,C#,Mysql,Entity Framework,Linq,Entity Framework Core,这看起来很简单,但我似乎无法解决它。使用efcore,我的DbContext中有一个DbSet规则 我试图编写一个查询,其中,给定IEnumerable行,给我DbSet中的所有规则,其中它的原始值是行中的一个元素,而不是值的子字符串 一段时间以来,我一直在使用类似于: private IQueryable<Rule> GetExistingRules() => dbContext.Rules.Where(r => lines.Contains(r.Raw));

这看起来很简单,但我似乎无法解决它。使用efcore,我的DbContext中有一个DbSet规则

我试图编写一个查询,其中,给定IEnumerable行,给我DbSet中的所有规则,其中它的原始值是行中的一个元素,而不是值的子字符串

一段时间以来,我一直在使用类似于:

private IQueryable<Rule> GetExistingRules() =>
    dbContext.Rules.Where(r => lines.Contains(r.Raw));
无法分析表达式 'valueMicrosoft.EntityFrameworkCore.Query.Internal.EntityQueryable'1[FilterList.Data.Entities.Rule].Intersect\u p\u 0, __p_1':当前不支持“System.Linq.Queryable.Intersect”方法的此重载

撰写此查询的最佳方式是什么?请注意,它位于DbContext交互链中,因此我更愿意将返回类型保留为IQueryable,以启用EF的惰性查询组合

更新:关于我怀疑Contains方法不起作用的原因的更多信息:

这是使用查询的类。我看到下面这样的异常,因为数据库中的原始列具有唯一的约束。我认为我在CreateNewRules中使用Except的逻辑可以防止规则中的任何行具有重复的原始值,但我的问题可能出在其他地方

public class SnapshotBatch
{
    private readonly FilterListsDbContext dbContext;
    private readonly IEnumerable<string> lines;
    private readonly Data.Entities.Snapshot snapEntity;

    public SnapshotBatch(FilterListsDbContext dbContext, IEnumerable<string> lines,
        Data.Entities.Snapshot snapEntity)
    {
        this.dbContext = dbContext;
        this.lines = lines;
        this.snapEntity = snapEntity;
    }

    public async Task SaveAsync()
    {
        var existingRules = GetExistingRules();
        var newRules = CreateNewRules(existingRules);
        dbContext.Rules.AddRange(newRules);
        var rules = existingRules.Concat(newRules);
        AddSnapshotRules(rules);
        await dbContext.SaveChangesAsync();
    }

    private IQueryable<Rule> GetExistingRules() =>
        dbContext.Rules.Where(r => lines.Contains(r.Raw));

    private List<Rule> CreateNewRules(IQueryable<Rule> existingRules) =>
        lines.Except(existingRules.Select(r => r.Raw))
             .Select(r => new Rule {Raw = r})
             .ToList();

    private void AddSnapshotRules(IQueryable<Rule> rules) =>
        snapEntity.AddedSnapshotRules
                  .AddRange(rules.Select(r => new SnapshotRule {Rule = r}));
}
异常StackTrace中的代码段,其中“Meebo:AdElement.Root”是规则表中Raw的示例值:

FilterLists.Services.Snapshot.Snapshot.TrySaveAsync in /home/travis/build/collinbarrett/FilterLists/src/FilterLists.Services/Snapshot/Snapshot.cs:line 43键“IX_rules_Raw”的重复条目“Meebo:AdElement.Root” MySql.Data.MySqlClient.MySqlDataReader.ActivateResultSetResultSet 结果集 C:\projects\mysqlconnector\src\mysqlconnector\MySql.Data.MySqlClient\MySqlDataReader.cs:line 93在


更新2:我相当肯定我看到的关于Contains的问题是由于它有一个问题。因为我的字符串有各种特殊字符,我认为它们在传递到Contains时没有正确转义,但它们似乎在联接中作为参数正确转义。

不要忘记,当您将linQ与EFCore和IQueryable一起使用时,它会在Sql语句中翻译c代码

你试过这个吗

var query = from rule in dbContext.Rules
            join line in lines
                on rule.Raw equals line
            select rule;

不要忘记,当您将linQ与EFCore和IQueryable一起使用时,它将转换Sql语句中的c代码

你试过这个吗

var query = from rule in dbContext.Rules
            join line in lines
                on rule.Raw equals line
            select rule;
你写道:

给我DbSet中的所有规则,其中它的原始值是行中的一个元素,精确匹配等

您的第一个解决方案将提供所需的结果:

var requestedRules = dbContext.Rules
   .Where(rule => lines.Contains(rule));
换句话说:从规则集合中,仅选择原始值等于行序列中某个值的规则

我得到了相同原始值的重复规则

很明显,你的源代码集合有相同原始值的规则

如果只需要唯一的原始值,则必须决定如何处理副本:

Id  Raw
 1  "Hello"
 2  "Hello"
你想要哪一个?第一个?最后?二者都没有一个有吗

让我们选择任何一个:我们将创建具有相同原始值的规则组,从每个组中,我们获取第一个规则,或者如果您想要最后一个,毕竟我们不在乎。但这样做的效率要低一点

var result = dbContext.Rules
   .Where(rule => lines.Contains(rule))
   .GroupBy(rule => rule.Raw)
   .Select(group => group.FirstOrDefault());
换句话说:从规则集合中,仅选择原始值等于行序列中某个值的规则。从其余元素中生成具有相同原始值的规则组。然后从每个组中选取任何元素,例如第一个元素

如果你想要全部/只想要第一个/只想要最后一个,你现在就知道该怎么做了。

你写道:

给我DbSet中的所有规则,其中它的原始值是行中的一个元素,精确匹配等

您的第一个解决方案将提供所需的结果:

var requestedRules = dbContext.Rules
   .Where(rule => lines.Contains(rule));
换句话说:从规则集合中,仅选择原始值等于行序列中某个值的规则

我得到了相同原始值的重复规则

很明显,你的源代码集合有相同原始值的规则

如果只需要唯一的原始值,则必须决定如何处理副本:

Id  Raw
 1  "Hello"
 2  "Hello"
你想要哪一个?第一个?最后?二者都没有一个有吗

让我们选择任何一个:我们将创建具有相同原始值的规则组,从每个组中,我们获取第一个规则,或者如果您想要最后一个,毕竟我们不在乎。但这样做的效率要低一点

var result = dbContext.Rules
   .Where(rule => lines.Contains(rule))
   .GroupBy(rule => rule.Raw)
   .Select(group => group.FirstOrDefault());
换句话说:从规则集合中,仅选择原始值等于行序列中某个值的规则。从其余元素中生成具有相同原始值的规则组。然后从每个组中选取任何元素,例如第一个元素


如果你想要全部/只想要第一个/只想要最后一个,你现在就知道该怎么做了。

你能再次解释一下Contains方法的问题吗,因为它似乎是从db获取现有规则的正确方法?@IvanStoev请参阅更新
在问题的底部。可能是我问了一个完全错误的问题。。。我不确定。异常似乎是由另一个代码Snapshot.TrySaveAsync生成的。最有可能的问题是由SnPosial.AdDeDeSpSoSturult.Ad[范围]引起的——如果SNAPnIt实体被附加到一个不同的上下文中,那么上下文的变化跟踪器可以考虑规则对象是Neo。SnPoStOfft批处理使用与它的调用者SnAPHOTH.TySavaSavyc相同的DbCurror实例。但是,由于Snapshot会启动SnapshotBatch的多个实例,我想知道是否由于所有内容都是异步的而存在冲突……请注意,数据库中的比较可能不区分大小写。因此,如果在数据库中有规则A,并且行中只包含A和A或A,那么您将获得现有规则:A,除A之外的行是A,因为C区分大小写,您将尝试插入A,这是数据库的一个副本。你能再次解释一下Contains方法有什么问题吗,因为它似乎是从db获取现有规则的正确方法?@IvanStoev请参阅问题底部的更新。可能是我问了一个完全错误的问题。。。我不确定。异常似乎是由另一个代码Snapshot.TrySaveAsync生成的。最有可能的问题是由SnPosial.AdDeDeSpSoSturult.Ad[范围]引起的——如果SNAPnIt实体被附加到一个不同的上下文中,那么上下文的变化跟踪器可以考虑规则对象是Neo。SnPoStOfft批处理使用与它的调用者SnAPHOTH.TySavaSavyc相同的DbCurror实例。但是,由于Snapshot会启动SnapshotBatch的多个实例,我想知道是否由于所有内容都是异步的而存在冲突……请注意,数据库中的比较可能不区分大小写。因此,如果在数据库中有规则A,并且行中只包含A和A或A,那么您将获得现有规则:A,除A之外的行是A,因为C区分大小写,您将尝试插入A,这是数据库的副本。初始测试似乎表明此方法比.contains更有效,将进行更多的完整测试,这将需要一些时间。我正在使用R转换的方法链语法dbContext.Rules.Joinlines,rule=>rule.Raw,line=>line,rule,line=>rule,但应该是等效的。我想知道Join是否比Contains更有效,因为我处理的是每…的大型数据集,尽管Contains也应该有效,将此标记为我正在使用的有效替代方案,至少直到我的问题中更新2中提到的问题得到解决。谢谢最初的测试似乎表明它比.Contains工作得更好,接下来将进行更多的完整测试,这将需要一些时间。我正在使用R转换的方法链语法dbContext.Rules.Joinlines,rule=>rule.Raw,line=>line,rule,line=>rule,但应该是等效的。我想知道Join是否比Contains更有效,因为我处理的是每…的大型数据集,尽管Contains也应该有效,将此标记为我正在使用的有效替代方案,至少直到我的问题中更新2中提到的问题得到解决。谢谢谢谢,哈罗德。在我的问题的Update下,我提到数据库中的Raw列有一个唯一的约束。因此,正如我问题底部的异常所证明的,数据库中已经没有重复的原始值。我怀疑我的问题与多个SnapshotBatch共享dbContext实例以异步方式运行有关。谢谢,Harald。在我的问题的Update下,我提到数据库中的Raw列有一个唯一的约束。因此,正如我问题底部的异常所证明的,数据库中已经没有重复的原始值。我怀疑我的问题与以异步方式运行的SnapshotBatch共享dbContext的多个实例有关。