代码之家  ›  专栏  ›  技术社区  ›  Collin Barrett

从DbSet<tenty>中获取属性值为IEnumerable的所有实体

  •  0
  • Collin Barrett  · 技术社区  · 6 年前

    DbSet<Rule> Rules 在我的 DbContext .

    public class Rule
    {
        public int Id { get; set; }
        public string Raw { get; set; }
    }
    

    IEnumerable<string> lines ,把所有的 Rule s来自 DbSet 在哪里 Raw 值是中的元素 lines (完全匹配,不是值的子字符串)。

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

    但是,我发现(我想)这并没有达到我的预期。(此方法之后立即插入新的 规则 所有元素的 目前还不存在。我被复制了 规则 同样的 生的 价值……)我想,相反,我需要用 .Intersect() ?

    我试着用一个定制的均衡器 this ,但它抛出了一个异常。

        private IQueryable<Rule> GetExistingRules()
        {
            var lineRules = lines.Select(l => new Rule {Raw = l});
            return dbContext.Rules.Intersect(lineRules, new RuleRawEqualityComparer());
        }
    
        private class RuleRawEqualityComparer : IEqualityComparer<Rule>
        {
            public bool Equals(Rule x, Rule y) => x?.Raw == y?.Raw;
            ...
        }
    

    无法分析表达式 '值(Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1[FilterLists.Data.Entities.Rule]).Intersect(\u p_0, __p_1)':当前不支持“System.Linq.Queryable.Intersect”方法的此重载。

    数据库上下文 交互,所以我更希望将返回类型保持为 IQueryable 以启用EF的惰性查询组合。

    Context on GitHub

    关于我为什么怀疑 Contains() 方法不起作用:

    这是正在使用查询的类。我看到下面这样的例外,因为 生的 Except() 在里面 CreateNewRules() Rules 有副本 生的 价值观,但也许我的问题在别处。。。

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

    生的 规则

    中的FilterLists.Services.Snapshot.Snapshot.trysavesync() /home/travis/build/collinbarrett/FilterLists/src/FilterLists.Services/Snapshot/Snapshot.cs:行 43重复条目“35;#######Meebo:AdElement.Root”用于键“IX_rules_Raw” MySql.Data.MySqlClient.MySqlDataReader.ActivateResultSet(结果集 结果集)在 C: \projects\mysqlconnector\src\mysqlconnector\MySql.Data.MySqlClient\MySqlDataReader.cs:line

    更新2 :我非常确定我看到的问题 包含() 是因为 this issue active PR . 因为我的字符串有各种各样的特殊字符,所以我认为它们在传入 包含() ,但它们似乎作为 Join() .

    2 回复  |  直到 6 年前
        1
  •  2
  •   Collin Barrett    6 年前

    不要忘记,当使用带有EFCore和IQueryable的linQ时,它会转换Sql语句中的c代码。

    var query = from rule in dbContext.Rules
                join line in lines
                    on rule.Raw equals line
                select rule;
    
        2
  •  2
  •   Harald Coppoolse    6 年前

    你写道:

    给出DbSet中的所有规则,其中原始值是行中的元素(精确匹配等)

    var requestedRules = dbContext.Rules
       .Where(rule => lines.Contains(rule));
    

    简而言之:来自 Rules 规则 Raw 值,该值等于 lines .

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

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

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

    Id  Raw
     1  "Hello"
     2  "Hello"
    

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

    var result = dbContext.Rules
       .Where(rule => lines.Contains(rule))
       .GroupBy(rule => rule.Raw)
       .Select(group => group.FirstOrDefault());
    

    简而言之:来自 规则 规则 有一个 生的 值,该值等于 线 . 从其余元素中创建具有相同原始值的规则组。然后从每个组中选取任何元素,例如第一个元素。