使用ienumerable中的属性值从dbset< tentity>获取所有实体

a8jjtwal  于 2021-06-20  发布在  Mysql
关注(0)|答案(2)|浏览(336)

这似乎很简单,但我似乎无法解决它。使用ef核心,我有一个 DbSet<Rule> Rules 在我的 DbContext .

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

我想写一个查询,如果 IEnumerable<string> lines ,把所有的 Rule 来自 DbSet 它在哪里 Raw 值是 lines (完全匹配,不是值的子字符串)。
有一段时间,我用的是:

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

但是,我后来发现(我想)这并没有达到我的预期(此方法之后立即插入新的 Rule 所有元素的 lines 目前不存在的。我被复制了 Rule 他和我一样 Raw 价值…)我想,相反,我需要使用 .Intersect() ?
我试着使用一个自定义的equalitycomparer,但是它抛出了一个异常。

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

无法分析表达式“value(microsoft.entityframeworkcore.query.internal.entityqueryable1[filterlists.data.entities.rule]).intersect(\u p\u 0,\u p\u 1)”:当前不支持方法“system.linq.queryable.intersect”的此重载。 撰写此查询的最佳方式是什么?请注意,它是在一个DbContext交互,所以我更喜欢将返回类型作为IQueryable启用ef的延迟查询组合。 github上的上下文 更新:更多关于我为什么怀疑Contains()方法无效: 这是使用查询的类。我看到如下例外情况,因为Raw数据库中的列具有唯一约束。我想我的逻辑(使用Except()CreateNewRules())会阻止Rules带副本Raw` 价值观,但也许我的问题在别处。。。

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'是的示例值 RawRules 表):
/home/travis/build/collinbarrett/filterlists/src/filterlists.services/snapshot/snapshot.cs中的filterlists.services.snapshot.snapshot.trysavesync():第43行重复条目'###meebo:adelement.root'对于mysql.data.mysqlclient.mysqldatareader.activateresultset(resultset resultset)中的键'ix\u rules\u raw'c:\projects\mysqlconnector\src\mysqlconnector\mysql.data.mysqlclient\mysqldatareader.cs:第93行
更新2:我很肯定我看到的问题 Contains() 是因为这个问题,有一个活动的公关。因为我的字符串有各种特殊字符,我认为他们没有得到正确转义时,传入 Contains() ,但它们似乎在 Join() .

xeufq47z

xeufq47z1#

不要忘记,当您将linq与efcore和iqueryable一起使用时,它会在sql语句中转换c代码。
你试过这个吗?

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

shyt4zoc2#

你写道:
给出dbset的所有规则,其中原始值是行中的元素(精确匹配等)
您的第一个解决方案将提供所需的结果:

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

大写:来自 Rules ,仅选择那些 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());

大写:来自 Rules ,仅选择那些 Rules 有一个 Raw 值,该值等于 lines . 从其余的元素中生成具有相同原始值的规则组。然后从每个组中选取任何元素,例如第一个元素。
如果你想要所有的/只有第一个/只有最后一个,你现在就知道该怎么办了。

相关问题