![](/img/trans.png)
[英]Entity Framework Core : get data from related tables with include
[英]Entity Framework Core include related data from table by string
我已經構建了一個小型應用程序,該應用程序使用了第三方SQL Server數據庫中的數據。 它們具有將對象鏈接在一起的結構:
一個名為“ Objecten”的表,用於保存最常用的數據,例如ObjectId,Unid,Name,Description等。所有這些對象都有一個“ ObjectType”列,該列是VARCHAR /字符串,例如:例如“ VRIJ1OBJECT
”, “ VRIJ2OBJECT
”,“ HARDWARE
”
相關數據存儲在具有以下名稱的表中:' VRIJ1OBJECTEN
',' VRIJ2OBJECTEN
',' HARDWARE
'。
在我的(ASP.NET Core)代碼中,我正在使用EF Core 2.0。 我嘗試返回帶有對象相關數據的(分頁)對象列表, 但是我不知道如何使用字符串名稱聯接表。
因此,當前,當我為頁面返回10個對象時,我正在執行11個查詢。 1獲取10個對象,每個對象獲取1個對象,以根據其ObjectType從表中獲取相關數據。 這大約需要3秒鍾,而1個查詢只需要200毫秒。 該API應該更快。
一些代碼:
private async Task<(List<ObjectViewModel> objecten, int totaalAantalObjecten)> _getTopDeskObjectenAsync(string q = null, string sort = "Naam-", int take = 0, int skip = 0, string e = null, bool qall = false, string categorie = "", RolstoelZoekenVM rolstoelZoekenVm = null, bool aotCategorie = false, AotZoekenVM aotZoekenVm = null)
{
var objecten = await _db.Object.Where(o => o.Status != -1).ToListAsync();
... (paging, filtering, ...) ...
var returnObjecten = new List<ObjectViewModel>();
foreach (var o in objecten){
returnObjecten.Add(await _dbObjectToViewModelAsync(o));
}
return (returnObjecten, totalCount);
}
private async Task<ObjectViewModel> _dbObjectToViewModelAsync(TopDeskDatabase.Object o)
{
var vrijObject = await GetDbVrijObjectAsync(o);
return new ObjectViewModel
{
... filling up the VM properties ...
}
}
// THIS should be done by the SQL Server in the query
public async Task<IVrijobject> GetDbVrijObjectAsync(TopDeskDatabase.Object o)
{
switch(o.Type.ToLower())
{
case "vrij1object":
return await _db.Vrij1object.FirstOrDefaultAsync(d => d.Objectid == o.Unid);
case "vrij2object":
return await _db.Vrij2object.FirstOrDefaultAsync(d => d.Objectid == o.Unid);
case "vrij3object":
return await _db.Vrij3object.FirstOrDefaultAsync(d => d.Objectid == o.Unid);
case "vrij4object":
return await _db.Vrij4object.FirstOrDefaultAsync(d => d.Objectid == o.Unid);
case "vrij5object":
return await _db.Vrij5object.FirstOrDefaultAsync(d => d.Objectid == o.Unid);
case "hardware":
return await _db.Hardware.FirstOrDefaultAsync(d => d.Objectid == o.Unid);
case "inventaris":
return await _db.Inventaris.FirstOrDefaultAsync(d => d.Objectid == o.Unid);
case "telefonie":
return await _db.Telefonie.FirstOrDefaultAsync(d => d.Objectid == o.Unid);
}
throw new InvalidDataException($"Object '{o.RefNaam}' is van type '{o.Type}', welke niet VRIJxOBJECT, INVENTARIS, TELEFONIE of HARDWARE is!");
}
您可以使用LEFT OUTER JOIN
為每種可能的返回類型創建查詢,存儲每種類型的結果對象,然后通過轉換為IVrijobject
來壓縮數據客戶端。
請參閱以下具有2種類型的示例(請注意,我是使用EF6創建的,因此EF Core可能需要進行一些更改)
public class ObjectModel
{
public int ID { get; set; }
public int ObjectTypeID { get; set; }
[StringLength(10)]
public string ObjectTypeDiscriminator { get; set; }
}
public interface IObjectTypeModel
{
int ID { get; set; }
string Data { get; set; }
}
// ObjectTypeDiscriminator = "Type1"
public class ObjectType1Model : IObjectTypeModel
{
public int ID { get; set; }
[StringLength(100)]
public string Data { get; set; }
}
// ObjectTypeDiscriminator = "Type2"
public class ObjectType2Model : IObjectTypeModel
{
public int ID { get; set; }
[StringLength(100)]
public string Data { get; set; }
}
class DbC : DbContext
{
public DbC()
{
}
public DbSet<ObjectModel> Objects { get; set; }
public DbSet<ObjectType1Model> Type1Objects { get; set; }
public DbSet<ObjectType2Model> Type2Objects { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
}
}
測試程序
class Program
{
static void Main(string[] args)
{
Database.SetInitializer(new DropCreateDatabaseAlways<DbC>());
// initialize some test data
using (var db = new DbC())
{
var t1_1 = db.Type1Objects.Add(new ObjectType1Model { Data = "Object T1 1" });
var t1_2 = db.Type1Objects.Add(new ObjectType1Model { Data = "Object T1 2" });
var t2_1 = db.Type2Objects.Add(new ObjectType2Model { Data = "Object T2 1" });
var t2_2 = db.Type2Objects.Add(new ObjectType2Model { Data = "Object T2 2" });
db.SaveChanges();
db.Objects.Add(new ObjectModel { ObjectTypeID = t1_1.ID, ObjectTypeDiscriminator = "Type1" });
db.Objects.Add(new ObjectModel { ObjectTypeID = t1_2.ID, ObjectTypeDiscriminator = "Type1" });
db.Objects.Add(new ObjectModel { ObjectTypeID = t2_1.ID, ObjectTypeDiscriminator = "Type2" });
db.Objects.Add(new ObjectModel { ObjectTypeID = t2_2.ID, ObjectTypeDiscriminator = "Type2" });
db.SaveChanges();
}
// fresh context for query demonstration
using (var db = new DbC())
{
db.Database.Log = x => Console.WriteLine(x);
var result =
from o in db.Objects
join t1 in db.Type1Objects on new { Discriminator = o.ObjectTypeDiscriminator, ObjectTypeID = o.ObjectTypeID } equals new { Discriminator = "Type1", ObjectTypeID = t1.ID } into types1
join t2 in db.Type2Objects on new { Discriminator = o.ObjectTypeDiscriminator, ObjectTypeID = o.ObjectTypeID } equals new { Discriminator = "Type2", ObjectTypeID = t2.ID } into types2
from t1 in types1.DefaultIfEmpty()
from t2 in types2.DefaultIfEmpty()
select new
{
Obj = o,
T1 = t1,
T2 = t2,
};
foreach (var item in result)
{
// only one concrete type will have a non-null value
var T = (IObjectTypeModel)item.T1 ?? item.T2;
Console.WriteLine("{0,20}{1,20}", item.Obj.ObjectTypeDiscriminator, T.Data);
}
}
Console.ReadKey();
}
}
輸出:
Opened connection at 06.12.2017 10:25:34 +01:00
SELECT
[Extent1].[ID] AS [ID],
[Extent1].[ObjectTypeID] AS [ObjectTypeID],
[Extent1].[ObjectTypeDiscriminator] AS [ObjectTypeDiscriminator],
[Extent2].[ID] AS [ID1],
[Extent2].[Data] AS [Data],
[Extent3].[ID] AS [ID2],
[Extent3].[Data] AS [Data1]
FROM [dbo].[ObjectModels] AS [Extent1]
LEFT OUTER JOIN [dbo].[ObjectType1Model] AS [Extent2]
ON ([Extent1].[ObjectTypeDiscriminator] = N'Type1') AND ([Extent1].[ObjectTypeID] = [Extent2].[ID])
LEFT OUTER JOIN [dbo].[ObjectType2Model] AS [Extent3]
ON ([Extent1].[ObjectTypeDiscriminator] = N'Type2') AND ([Extent1].[ObjectTypeID] = [Extent3].[ID])
-- Executing at 06.12.2017 10:25:34 +01:00
-- Completed in 6 ms with result: SqlDataReader
Type1 Object T1 1
Type1 Object T1 2
Type2 Object T2 1
Type2 Object T2 2
Closed connection at 06.12.2017 10:25:34 +01:00
如您所見,生成的查詢將為每個對象使用單獨的結果列,其效率可能會或可能不會比基於區分項的結果合並效率低(我沒有對此方面進行調查)。 如果您的Unid
足夠獨特,那么您不需要Unid
條件的Discriminator
部分。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.