[英]How to insert an existing IQueryable element to a ThenInclude method in EF Core
[英]How to query IQueryable with Include - ThenInclude?
在 .NET Core 2.2 中,我堅持過濾IQueryable
構建為:
_context.Ports.Include(p => p.VesselsPorts)
.ThenInclude(p => p.Arrival)
.Include(p => p.VesselsPorts)
.ThenInclude(p => p.Departure)
.OrderBy(p => p.PortLocode);
在多對多的關系中。 實體模型如下:
public class PortModel
{
[Key]
public string PortLocode { get; set; }
public double? MaxKnownLOA { get; set; }
public double? MaxKnownBreadth { get; set; }
public double? MaxKnownDraught { get; set; }
public virtual ICollection<VesselPort> VesselsPorts { get; set; }
}
public class VesselPort
{
public int IMO { get; set; }
public string PortLocode { get; set; }
public DateTime? Departure { get; set; }
public DateTime? Arrival { get; set; }
public VesselModel VesselModel { get; set; }
public PortModel PortModel { get; set; }
}
基於this SO answer我設法像這樣創建 LINQ :
_context.Ports.Include(p => p.VesselsPorts).ThenInclude(p => p.Arrival).OrderBy(p => p.PortLocode)
.Select(
p => new PortModel
{
PortLocode = p.PortLocode,
MaxKnownBreadth = p.MaxKnownBreadth,
MaxKnownDraught = p.MaxKnownDraught,
MaxKnownLOA = p.MaxKnownLOA,
VesselsPorts = p.VesselsPorts.Select(vp => vp.Arrival > DateTime.UtcNow.AddDays(-1)) as ICollection<VesselPort>
}).AsQueryable();
但我需要找到所有端口記錄,其中: VesselsPorts.Arrival > DateTime.UtcNow.AddDays(-1)
數量大於int x = 5
值(例如)。 而且我不知道該怎么做:/
感謝@GertArnold評論,我最終得到了查詢:
ports = ports.Where(p => p.VesselsPorts.Where(vp => vp.Arrival > DateTime.UtcNow.AddDays(-1)).Count() > x);
當使用實體框架時,人們傾向於使用Include
而不是Select
來節省一些打字。 這樣做很少是明智的。
DbContext
包含一個ChangeTracker
。 在 DbContext 的生命周期內從任何表中獲取的每個完整行都存儲在 ChangeTracker 中,以及一個克隆。 您將獲得對副本的引用。 (或者可能是對原件的引用)。 如果您更改所獲得數據的屬性,它們會在 ChangeTracker 中的副本中更改。 在 SaveChanges 期間,將原始數據與副本進行比較,以查看是否必須保存數據。
因此,如果您要獲取大量數據並使用include
,那么每個獲取的項目都會被克隆。 這可能會大大減慢您的查詢速度。
除了這種克隆之外,您可能會獲取比實際計划使用更多的屬性。 數據庫管理系統在組合表格和在表格中搜索行方面得到了極大的優化。 較慢的部分之一是將所選數據傳輸到本地進程。
例如,如果您有一個包含學校和學生的數據庫,具有明顯的一對多關系,那么每個學生都會有一個指向他就讀的學校的外鍵。
因此,如果您要求 School [10] 和他的 2000 個學生,那么每個學生的外鍵值為 [10]。 如果您使用Include
,那么您將傳輸相同的值 10 超過 2000 次。 多么浪費處理能力!
在實體框架中,查詢數據時,始終使用
Select
到 select 屬性,而 Select 僅使用您實際計划使用的屬性。 僅當您計划更改獲取的項目時才使用Include
。
當然不要使用Include
來節省您的打字時間!
要求:給我港口和他們的船只
var portsWithTheirVessels = dbContext.Ports
.Where(port => ...) // if you don't want all Ports
.Select(port => new
{
// only select the properties that you want:
PortLocode = port.PortLoCode,
MaxKnownLOA = port.MaxKnownLOA,
MaxKnownBreadth = prot.MaxKnownBreadth,
MaxKnownDraught = ports.MaxKnownDraught,
// The Vessels in this port:
Vessels = port.VesselsPort.Select(vessel => new
{
// again: only the properties that you plan to use
IMO = vessel.IMO,
...
// do not select the foreign key, you already know the value!
// PortLocode = vessle.PortLocode,
})
.ToList(),
});
實體框架知道您的一對多關系,並且知道如果您使用虛擬 ICollection,它應該執行 (Group-)Join。
有些人更喜歡自己進行 Group-Join,或者他們使用不支持使用 ICollection 的實體框架版本。
var portsWithTheirVessels = dbContext.Ports.GroupJoin(dbContext.VesselPorts,
port => port.PortLocode, // from every Port take the primary key
vessel => vessel.PortLocode, // from every Vessel take the foreign key to Port
// parameter resultSelector: take every Port with its zero or more Vessels to make one new
(port, vesselsInThisPort) => new
{
PortLocode = port.PortLoCode,
...
Vessels = vesselsInThisPort.Select(vessel => new
{
...
})
.ToList(),
});
選擇:
var portsWithTheirVessels = dbContext.Ports.Select(port => new
{
PortLocode = port.PortLoCode,
...
Vessels = dbContext.VesselPorts.Where(vessel => vessel.PortLocode == port.PortLocode)
.Select(vessel => new
{
...
}
.ToList(),
});
實體框架也將其轉換為 GroupJoin。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.