我正在使用 SQL Server 2019 和 EF Core 8。
我有两个实体,
TenantOrganization
(组织)和 SharedIndustry
(行业),它们通过加入实体 TenantOrganizationIndustries
(组织行业)具有多对多关系。从行业的 ID 开始,我想计算与其相关的 OrganizationIndustries 的数量,以便我可以允许或拒绝删除该行业。 Shared
和 Tenant
是数据库中的模式。
我遇到的问题是 EF Core 生成了错误的查询,并且错误地命名了查询中联接中的表。具体来说,它将
[Tenant].[Organizations]
命名为 [TenantOrganization]
,忽略名称的架构部分,并将表的名称单数化。
这是正在生成的查询:
SELECT TOP(1) (
SELECT COUNT(*)
FROM [Tenant].[OrganizationIndustries] AS [o]
INNER JOIN [TenantOrganization] AS [t] ON [o].[OrganizationId] = [t].[Id]-- WRONG table name
WHERE [i].[Id] = [o].[IndustryId])
FROM [Shared].[Industries] AS [i]
WHERE [i].[Id] = @__command_Id_0
查询的正确版本是这样的(根据我的口味重新格式化):
SELECT TOP(1) (
SELECT COUNT(*)
FROM [Tenant].[OrganizationIndustries] AS [TOI]
INNER JOIN [Tenant].[Organizations] AS [TO] ON ([TOI].[OrganizationId] = [TO].[Id])-- CORRECT table name
WHERE ([SI].[Id] = [TOI].[IndustryId])
)
FROM [Shared].[Industries] AS [SI]
WHERE ([SI].[Id] = @__command_Id_0);
这是我正在使用的 LINQ 查询,用于创建生成的查询:
_shared.Industries.Where(i => i.Id == command.Id).Select(i => i.Organizations.Count).FirstAsync(cancellationToken)
这是
DbContext
中实体的导航配置:
builder.Entity<TenantOrganization>().HasMany(
to => to.Industries).WithMany(
si => si.Organizations).UsingEntity(
"OrganizationIndustries",
l => l.HasOne(typeof(SharedIndustry)).WithMany().HasForeignKey(nameof(TenantOrganizationIndustry.IndustryId)).HasPrincipalKey(nameof(SharedIndustry.Id)),
r => r.HasOne(typeof(TenantOrganization)).WithMany().HasForeignKey(nameof(TenantOrganizationIndustry.OrganizationId)).HasPrincipalKey(nameof(TenantOrganization.Id)),
j => j.ToTable("OrganizationIndustries", "Tenant"));
最后是 EF Core 模型:
public sealed class SharedIndustry {
public SharedIndustryId Id { get; set; }
public ICollection<TenantOrganization> Organizations { get; } = [];
}
public sealed class TenantOrganization {
public TenantOrganizationId Id { get; set; }
public ICollection<SharedIndustry> Industries { get; } = [];
}
public sealed class TenantOrganizationIndustry {
public SharedIndustryId IndustryId { get; set; }
public TenantOrganizationId OrganizationId { get; set; }
}
如何让 EF Core 生成正确的查询,特别是为表使用正确的名称?我这样做时没有使用
DbSet
来表示 TenantOrganizationIndustry
,但我开始怀疑我是否必须这样做才能使其发挥作用。
实际上,应该生成的最佳查询是:
SELECT COUNT(*)
FROM [Tenant].[OrganizationIndustries]
WHERE ([IndustryId] = @__command_Id_0);
但我认为如果没有
DbSet
的 TenantOrganizationIndustry
我就无法做到。目前我想看看是否可以正确定义这个多对多连接,以便生成正确的查询。
如果能帮助实现这一目标,我们将不胜感激!
老实说,我不知道它最终如何工作,但我决定使用 EF Core Power Tools 对数据库进行逆向工程,看看它对多对多关系有何作用。在 Visual Studio 2022 中的 GUI 版本毫无进展后,我最终使用 CLI 版本对模型进行逆向工程,并复制了它为关系所做的配置。
值得注意的是,它应用了行业配置,而不是像我一样应用在组织上。我猜这只是因为它是按字母顺序排列的两个对象中的第一个。
我稍微调整了它,所以它不使用
Dictionary<string, object>
而是我的 TenantOrganizationIndustry
对象。这是当前工作版本:
builder.HasMany(
si => si.Organizations).WithMany(
to => to.Industries).UsingEntity<TenantOrganizationIndustry>(
nameof(TenantOrganizationIndustry),
r => r.HasOne<TenantOrganization>().WithMany().HasForeignKey(toi => toi.OrganizationId),
l => l.HasOne<SharedIndustry>().WithMany().HasForeignKey(toi => toi.IndustryId),
j => {
j.ToTable("OrganizationIndustries", Schemas.Tenant).HasKey(toi => new {
toi.IndustryId,
toi.OrganizationId
});
j.Property(
toi => toi.IndustryId).HasConversion<SharedIndustryId.EfCoreValueConverter>();
j.Property(
toi => toi.OrganizationId).HasConversion<TenantOrganizationId.EfCoreValueConverter>();
});