【问题标题】:InvalidOperation when Get Items from Sqlite and Remove Duplicate items从 Sqlite 获取项目并删除重复项目时的 InvalidOperation
【发布时间】:2021-08-28 23:07:48
【问题描述】:

我想从 sqlite 数据库中获取项目(数据库中大约有 6,000 个项目) 有些物品是重复的因此,我想在获得物品时删除此重复信息

我使用了以下代码

public async static Task<List<myModel>> GetAllItems()
        {
            using var db = new dbContext();
            var query =
                from item in db.myTable.GroupBy(x => x.Id).Select(x => x.First())
                select new myModel
                {
                    Id = item.Id,
                    Name = item.Name,
                    ...
                };
            return await query.ToListAsync();
        }

但我收到以下错误

System.InvalidOperationException: 'The LINQ expression 'GroupByShaperExpression:
KeySelector: m.Id, 
ElementSelector:EntityShaperExpression: 
    EntityType: myTable
    ValueBufferExpression: 
        ProjectionBindingExpression: EmptyProjectionMember
    IsNullable: False

    .First()' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.'

【问题讨论】:

  • 请提供EF Core版本。
  • @IvanStoev Microsoft.EntityFrameworkCore.Sqlite 5.0.6

标签: c# entity-framework-core


【解决方案1】:

更新(EF Core 6.0):

EF Core 6.0 确实向GroupBy 结果集添加了对一些额外运算符的支持,包括有问题的运算符,因此现在原始 LINQ 查询应该可以正常工作。

原文:

由于目前(希望 v6.0 会添加一些)EF Core 不支持 GroupBy 除键/聚合投影之外的结果运算符,它不能用于实现 每组前 N 个项目函数,这就是你基本上想要做的(对于N == 1)。

因此,作为一种解决方法(没有第 3 方扩展),您必须手动执行此操作,方法是 (1) 使用子查询来选择唯一键,然后 (2) 将其用作相关限制子查询的过滤器。例如像

var query = db.myTable.Select(x => new { x.Id }).Distinct() // (1)
    .SelectMany(key => db.myTable.Where(x => x.Id == key.Id).Take(1)) // (2)
    // The rest is the same as the original
    .Select(item => new myModel
    {
        Id = item.Id,
        Name = item.Name,
        ...
    });

【讨论】:

  • 不错的解决方案伊万!
  • 感谢@Svyatoslav,你知道的穷人把戏 :-) 可悲的是,最终的 SQL 查询连接了 2 个子查询,而第二个正是需要的 (ROW_NUMBER() OVER...)
  • 谢谢,您的代码运行良好,只是一个问题,您的方法更好还是马赫迪给出的答案更好?更好意味着更快地加载和处理大量数据(5000 到 20000)
  • @gittest 在其他答案下查看我的评论。不同之处在于这是在服务器端执行并仅返回所需的数据,而另一个检索所有数据然后在内存中执行分组/过滤。因此,我认为这通常会更好。实际上,这取决于数据库表中有多少重复项,以及它有多少属性(列)。
【解决方案2】:

首先,将您的var 更改为IEnumerable&lt;HWGPackageModel&gt;

其次,在GroupBy前添加AsEnumerable()

public static IEnumerable<myModel> GetAllItems()
        {
            
            var db = new dbContext();
            IEnumerable<myModel> query =
            from item in db.myTable.AsEnumerable().GroupBy(x => x.Id).Select(x => x.FirstOrDefault())
            select new myModel
                {
                    Id = item.Id,
                    ...
                };

            return query;
        }

【讨论】:

  • 这将在内存中执行操作(在从数据库中检索所有项目之后),这通常是不好的,并且是在 EFC 3.0 中删除客户端评估的主要原因
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-17
相关资源
最近更新 更多