Entity Framework 基于可空主键列分组
Entity Framework Group by based on a Nullable Primary Key column
我用于存储地址的实体如下所示,并引用多个 table 作为外键,如国家大陆等
public class ContactAddress
{
[Key]
public int Id { get; set; }
[ForeignKey(nameof(Contact))]
public int ContactId { get; set; }
public virtual Contact Contact { get; set; }
[ForeignKey(nameof(Continent))]
public int? ContinentId { get; set; }
public virtual Continent Continent { get; set; }
[ForeignKey(nameof(Country))]
public int? CountryId { get; set; }
public virtual Country Country { get; set; }
}
尝试获取国家/地区和大陆地址值的计数,并将结果映射到 List<GeoStatsModel>
,类似于
public class GeoStatsModel
{
public int Id { get; set; } // Country Id
public string Name { get; set; } //Country Name
public int Count { get; set; }
}
设法生成如下查询
List<GeoStatsModel> response = new List<GeoStatsModel>();
response = context.ContactAddresses
.Where(a => a.IsPrimary == true && contactIds.Contains(a.ContactId))
.GroupBy(a => a.CountryId)
.Select(g => new GeoStatsModel
{
Id = (int)g.Key,
Name = (g.First().Country!=null)? g.First().Country.Name: "",
Count = g.Count()
}).ToList();
执行的时候报错:
The LINQ expression 'GroupByShaperExpression: KeySelector:
(Nullable)c.CountryId, ElementSelector:EntityShaperExpression:
EntityType: ContactAddress
ValueBufferExpression:
ProjectionBindingExpression: EmptyProjectionMember
IsNullable: False
.Select(s => s.Country) .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.
我们如何才能正确地 return 来自外键 table 的名称并对结果进行分组?
GroupBy
对 EF 核心的支持有限。它基本上支持SQL支持的语句,在EF core 6中多一点。
在 SQL 中,不可能按 CountryId
分组并在结果集中包含国家名称(至少不是在所有 RDBMS 中)。要在 SQL 中执行此操作,该语句应与 Country
连接,然后按 CountryId
和 Country.Name
分组。这就是 EF 还支持的内容:
var response = context.ContactAddresses
.Where(a => a.IsPrimary && contactIds.Contains(a.ContactId))
.GroupBy(a => new { a.CountryId, a.Country.Name })
.Select(g => new GeoStatsModel
{
Id = g.Key.CountryId ?? 0,
Name = g.Key.Name ?? string.Empty,
Count = g.Count()
}).ToList();
我用于存储地址的实体如下所示,并引用多个 table 作为外键,如国家大陆等
public class ContactAddress
{
[Key]
public int Id { get; set; }
[ForeignKey(nameof(Contact))]
public int ContactId { get; set; }
public virtual Contact Contact { get; set; }
[ForeignKey(nameof(Continent))]
public int? ContinentId { get; set; }
public virtual Continent Continent { get; set; }
[ForeignKey(nameof(Country))]
public int? CountryId { get; set; }
public virtual Country Country { get; set; }
}
尝试获取国家/地区和大陆地址值的计数,并将结果映射到 List<GeoStatsModel>
,类似于
public class GeoStatsModel
{
public int Id { get; set; } // Country Id
public string Name { get; set; } //Country Name
public int Count { get; set; }
}
设法生成如下查询
List<GeoStatsModel> response = new List<GeoStatsModel>();
response = context.ContactAddresses
.Where(a => a.IsPrimary == true && contactIds.Contains(a.ContactId))
.GroupBy(a => a.CountryId)
.Select(g => new GeoStatsModel
{
Id = (int)g.Key,
Name = (g.First().Country!=null)? g.First().Country.Name: "",
Count = g.Count()
}).ToList();
执行的时候报错:
The LINQ expression 'GroupByShaperExpression: KeySelector: (Nullable)c.CountryId, ElementSelector:EntityShaperExpression: EntityType: ContactAddress ValueBufferExpression: ProjectionBindingExpression: EmptyProjectionMember IsNullable: False
.Select(s => s.Country) .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.
我们如何才能正确地 return 来自外键 table 的名称并对结果进行分组?
GroupBy
对 EF 核心的支持有限。它基本上支持SQL支持的语句,在EF core 6中多一点。
在 SQL 中,不可能按 CountryId
分组并在结果集中包含国家名称(至少不是在所有 RDBMS 中)。要在 SQL 中执行此操作,该语句应与 Country
连接,然后按 CountryId
和 Country.Name
分组。这就是 EF 还支持的内容:
var response = context.ContactAddresses
.Where(a => a.IsPrimary && contactIds.Contains(a.ContactId))
.GroupBy(a => new { a.CountryId, a.Country.Name })
.Select(g => new GeoStatsModel
{
Id = g.Key.CountryId ?? 0,
Name = g.Key.Name ?? string.Empty,
Count = g.Count()
}).ToList();