簡體   English   中英

實體框架核心按字符串包括表中的相關數據

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM