我已经构建了一个小应用程序,它使用来自第三方的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!");
}
答案 0 :(得分:0)
您可以为每种可能的返回类型创建一个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
足够独特,那么您不需要加入条件的Discriminator
部分。