[英]How to get Inner Join using navigation property in Entity Framework Core
我想生成一個查詢,該查詢使用導航屬性對一對一關系使用內部聯接。 這是針對我無法更改的現有數據庫。
這是我的實體的樣子:
[Table("Info")]
public class Info
{
[Key]
public int InfoId { get; set; }
public string Name { get; set; }
public virtual MoreInfo MoreInfo { get; set; }
}
[Table("MoreInfo")]
public class MoreInfo
{
[Key]
public int InfoId { get; set; }
public string OtherName { get; set; }
public int OtherNumber { get; set; }
}
這是我的查詢:
var x = await context.Infos
.Select(info => new
{
info.InfoId,
info.Name,
info.MoreInfo.OtherName,
info.MoreInfo.OtherNumber
})
.ToListAsync();
這會生成此 SQL(使用左連接):
SELECT [info].[InfoId], [info].[Name], [info.MoreInfo].[OtherName], [info.MoreInfo].[OtherNumber]
FROM [Info] AS [info]
LEFT JOIN [MoreInfo] AS [info.MoreInfo] ON [info].[InfoId] = [info.MoreInfo].[InfoId]
如果 Info 中有不在 MoreInfo 中的記錄,這將導致錯誤,這就是為什么我要進行內部聯接。
我在 OnModelCreating 中嘗試了各種選項,例如
modelBuilder.Entity<Info>()
.HasOne(p => p.MoreInfo)
.WithOne()
.IsRequired();
或將導航屬性設置為必需
[Table("Info")]
public class Info
{
[Key]
public int InfoId { get; set; }
public string Name { get; set; }
[Required]
public virtual MoreInfo MoreInfo { get; set; }
}
或在查詢中使用包含
var x = await context.Infos
.Include(info => info.MoreInfo)
.Select(info => new
{
info.InfoId,
info.Name,
info.MoreInfo.OtherName,
info.MoreInfo.OtherNumber
})
.ToListAsync();
但這些都沒有改變加入。
我可以通過使用 join 函數而不是使用導航屬性來獲得內部聯接,但如果可能的話,我想避免這種情況。 語法很難看,需要我將 MoreInfos 添加到上下文中。 如果可能,我想使用導航屬性創建內部聯接。
var x = await context.Infos
.Join(context.MoreInfos, info => info.InfoId, moreInfo => moreInfo.InfoId, (info, moreInfo) =>
new
{
info.InfoId,
info.Name,
moreInfo.OtherName,
moreInfo.OtherNumber
})
.ToListAsync();
生成正確的 SQL
SELECT [info].[InfoId], [info].[Name], [moreInfo].[OtherName], [moreInfo].[OtherNumber]
FROM [Info] AS [info]
INNER JOIN [MoreInfo] AS [moreInfo] ON [info].[InfoId] = [moreInfo].[InfoId]
但我寧願使用導航屬性。
當前(EF Core 2.1.2)無法使用提供的模型。
真正的一對一關系在技術上無法強制執行,因此 EF Core IsRequired
表示依賴實體 FK 是否可為空。 對於像您這樣的共享 PK 協會來說,這始終是正確的。 請注意, Info
是主體,而MoreInfo
是從屬,因此MoreInfo
需要Info
,反之亦然,這就是 EF Core 在從主體導航到從屬時生成左外連接的原因。
您可以做的一件事是包含非空條件:
.Where(info => info.MoreInfo != null)
當在 EF6 查詢(帶有一些中間投影)中使用時,能夠讓 EF6 查詢轉換器使用內連接。 EF Core 仍然不夠智能,因此所有這些技巧都不起作用。 它生成帶有右側鍵IS NOT NULL
過濾器的左外連接。 這等效於內部聯接,並且可能會由 SQL 查詢優化器進行處理。 但是還是...
當前獲得內部聯接的唯一方法(當然手動聯接除外)是從關系的另一端導航,即從依賴關系到所需主體。 無需從上下文公開DbSet<MoreInfo>
, Set<TEntity>()
方法可用於訪問任何實體集。 不過,您需要一個反向導航屬性:
public class MoreInfo
{
// ...
public virtual Info Info { get; set; }
}
當然還有更新的流暢配置:
modelBuilder.Entity<Info>()
.HasOne(e => e.MoreInfo)
.WithOne(e => e.Info)
.HasForeignKey<MoreInfo>(e => e.InfoId);
現在查詢可以改寫為:
var x = await context.Set<MoreInfo>()
.Select(moreInfo => new
{
moreInfo.Info.InfoId,
moreInfo.Info.Name,
moreInfo.OtherName,
moreInfo.OtherNumber
})
.ToListAsync();
這將生成所需的內部連接:
SELECT [moreInfo].[InfoId], [moreInfo.Info].[Name], [moreInfo].[OtherName], [moreInfo].[OtherNumber]
FROM [MoreInfo] AS [moreInfo]
INNER JOIN [Info] AS [moreInfo.Info] ON [moreInfo].[InfoId] = [moreInfo.Info].[InfoId]
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.