如何解决抛出异常使用流利的API从组中获取项目 A返回所有WAContact实体 B仅返回所有带有相关WAContact实体的WAUser ID完整 C返回带有或不带有相关WAContact实体完整的所有WAUser实体完整示例程序其他信息
这是我要完成的查询:
var contacts = await dbContext.Contacts
.GroupBy(o => o.UserId)
.Select(group => new
{
UserId = group.Key,Contacts = group.ToList()
}).ToListAsync();
这是联系人实体:
[Table("Contacts")]
public class WAContact
{
public int Id { get; set; }
public string Phone { get; set; }
public string Name { get; set; }
[NotNull]
public int UserId { get; set; }
public WAUser User { get; set; }
}
此代码引发此异常:
.ToList()'无法翻译。用表格重写查询 可以翻译,或通过以下方式明确转换为客户评估 插入对AsEnumerable(),AsAsyncEnumerable()的调用, ToList()或ToListAsync()。
我已经看到示例执行ToList()来检索组项目没有问题,但是,我不知道代码中正在发生什么。
P.D。经过更多测试后,我注意到调用First(),Last()等也会遇到相同的错误。但是,例如Count()可以工作。奇怪!
解决方法
这是问题。 联系人= group.ToList()
为什么不更改代码,如
var grouprs= await dbContext.Contacts.Select(c=>c)
.GroupBy(o => o.UserId);
,
您将收到此异常,因为EF无法将LINQ转换为等效的SQL。
将查询更改为此
// Load the Contact from the DB
var contacts = await dbContext.Contacts.ToListAsync();
// Perform the group by in memory
var userContacts = contacts
.GroupBy(o => o.UserId)
.Select(group => new
{
UserId = group.Key,Contacts = group.Select(contact => new
{
contact.Name,contact.Phone,contact.Id
}).ToList()
}).ToList();
现在,EF将能够将LINQ转换为适当的SQL。
,此查询不可翻译为SQL。 我为此类错误写了一个小答案,您的查询位于列表的顶部:LINQ to Database: how to group entities properly and GroupBy limitations
,您可以根据所需的结果以多种方式实现所需的查询:
A)返回所有WAContact实体
因为每个实体都必须有一个UserId,所以不需要实际查询WAUsers表:
var userIdsWithContactsWithoutJoin = context.Contacts
.AsEnumerable()
.GroupBy(c => c.UserId)
.ToList();
代码仅执行SELECT
,然后切换到客户端评估以将返回的数据分组到内存中。
SELECT `c`.`Id`,`c`.`Name`,`c`.`Phone`,`c`.`UserId`
FROM `Contacts` AS `c`
B)仅返回所有带有相关WAContact实体的WAUser ID(完整)
var userIdsWithContacts = context.Users
.SelectMany(
u => context.Contacts
.Where(c => u.Id == c.UserId),(u,c) => new
{
c.UserId,Contact = c
})
.AsEnumerable()
.GroupBy(j => j.UserId,j => j.Contact)
.ToList();
代码首先执行INNER JOIN
,然后切换到客户端评估以将返回的数据分组到内存中>
SELECT `c`.`UserId`,`c`.`Id`,`c`.`Phone`
FROM `Users` AS `u`
INNER JOIN `Contacts` AS `c` ON `u`.`Id` = `c`.`UserId`
C)返回带有或不带有相关WAContact实体(完整)的所有WAUser实体(完整)
var usersWithOrWithoutContacts = context.Users
.SelectMany(
u => context.Contacts
.Where(c => u.Id == c.UserId)
.DefaultIfEmpty(),c) => new
{
User = u,Contact = c
})
.AsEnumerable()
.GroupBy(j => j.User,j => j.Contact)
.ToList();
代码首先执行LEFT JOIN,然后切换到客户端评估以将返回的数据分组到内存中>
SELECT `u`.`Id`,`u`.`Name`,`c`.`UserId`
FROM `Users` AS `u`
LEFT JOIN `Contacts` AS `c` ON `u`.`Id` = `c`.`UserId`
所有三个查询都返回尽可能少的数据,然后使用AsEnumerable()
切换到客户端评估以在内存中执行实际分组。
示例程序
这是一个可以正常运行的示例项目,它演示了查询(包括检查):
using System.ComponentModel.DataAnnotations.Schema;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure;
namespace IssueConsoleTemplate
{
[Table("Contacts")]
public class WAContact
{
public int Id { get; set; }
public string Phone { get; set; }
public string Name { get; set; }
[NotNull]
public int UserId { get; set; }
public WAUser User { get; set; }
}
[Table("Users")]
public class WAUser
{
public int Id { get; set; }
public string Name { get; set; }
}
//
// DbContext:
//
public class Context : DbContext
{
public DbSet<WAContact> Contacts { get; set; }
public DbSet<WAUser> Users { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder
.UseMySql(
"server=127.0.0.1;port=3306;user=root;password=;database=So64391764",b => b.ServerVersion("8.0.21-mysql")
.CharSetBehavior(CharSetBehavior.NeverAppend))
.UseLoggerFactory(
LoggerFactory.Create(
b => b
.AddConsole()
.AddFilter(level => level >= LogLevel.Information)))
.EnableSensitiveDataLogging()
.EnableDetailedErrors();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<WAUser>()
.HasData(
new WAUser {Id = 1,Name = "John"},new WAUser {Id = 2,Name = "Jane"},new WAUser {Id = 3,Name = "Mike"});
modelBuilder.Entity<WAContact>()
.HasData(
new WAContact {Id = 11,Name = "John's First Contact",Phone = "12345",UserId = 1},new WAContact {Id = 12,Name = "John's Second Contact",Phone = "23456",new WAContact {Id = 21,Name = "Jane's Only Contact",Phone = "09876",UserId = 2});
}
}
internal class Program
{
private static void Main()
{
using var context = new Context();
context.Database.EnsureDeleted();
context.Database.EnsureCreated();
// Return all WAContact entities. Because every entity must have a UserId,// there is no need to actually query the WAUsers table.
// Just performs a SELECT,then switches to client-evaluation to group the returned
// data in memory:
// SELECT `c`.`Id`,`c`.`UserId`
// FROM `Contacts` AS `c`
var userIdsWithContactsWithoutJoin = context.Contacts
.AsEnumerable()
.GroupBy(c => c.UserId)
.ToList();
Debug.Assert(userIdsWithContactsWithoutJoin.Count == 2);
Debug.Assert(userIdsWithContactsWithoutJoin[0].Key == 1);
Debug.Assert(userIdsWithContactsWithoutJoin[0].Count() == 2);
Debug.Assert(userIdsWithContactsWithoutJoin[0].First().Name == "John's First Contact");
// Return all WAUser Ids only with related WAContact entities (full).
// First performs an INNER JOIN,then switches to client-evaluation to group the
// returned data in memory:
// SELECT `c`.`UserId`,`c`.`Phone`
// FROM `Users` AS `u`
// INNER JOIN `Contacts` AS `c` ON `u`.`Id` = `c`.`UserId`
var userIdsWithContacts = context.Users
.SelectMany(
u => context.Contacts
.Where(c => u.Id == c.UserId),c) => new
{
c.UserId,Contact = c
})
.AsEnumerable()
.GroupBy(j => j.UserId,j => j.Contact)
.ToList();
Debug.Assert(userIdsWithContacts.Count == 2);
Debug.Assert(userIdsWithContacts[0].Key == 1);
Debug.Assert(userIdsWithContacts[0].Count() == 2);
Debug.Assert(userIdsWithContacts[0].First().Name == "John's First Contact");
// Return all WAUser entities (full) with or without related WAContact entities (full).
// First performs a LEFT JOIN,then switches to client-evaluation to group the returned
// data in memory:
// SELECT `u`.`Id`,`c`.`UserId`
// FROM `Users` AS `u`
// LEFT JOIN `Contacts` AS `c` ON `u`.`Id` = `c`.`UserId`
var usersWithOrWithoutContacts = context.Users
.SelectMany(
u => context.Contacts
.Where(c => u.Id == c.UserId)
.DefaultIfEmpty(),c) => new
{
User = u,Contact = c
})
.AsEnumerable()
.GroupBy(j => j.User,j => j.Contact)
.ToList();
Debug.Assert(usersWithOrWithoutContacts.Count == 3);
Debug.Assert(usersWithOrWithoutContacts[0].Key.Name == "John");
Debug.Assert(usersWithOrWithoutContacts[0].Count() == 2);
Debug.Assert(usersWithOrWithoutContacts[0].First().Name == "John's First Contact");
}
}
}
您也可以运行此.NET Fiddle(但使用SQL Server而不是MySQL)。
其他信息
有关GROUP BY
查询的一般信息,请查看Complex Query Operators。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。