0

제 3 자의 SQL Server 데이터베이스에서 가져온 데이터를 사용하는 작은 응용 프로그램을 만들었습니다.Entity Framework Core에서 테이블의 관련 데이터를 문자열로 포함합니다.

ObjectId, Unid, Name, Description 등의 가장 일반적인 데이터를 유지하는 'Objecten'이라는 테이블에는 'ObjectType'이 있습니다. VARCHAR/스트링 인 컬럼과 같은 예 'VRIJ1OBJECT', 'VRIJ2OBJECT', 'HARDWARE'용

관련 데이터는 이러한 이름 테이블에 저장된다

VRIJ1OBJECTEN」, 「VRIJ2OBJECTEN ','HARDWARE ' .

내 (ASP.NET 코어) 코드에서 EF Core 2.0을 사용하고 있습니다. 관련된 데이터 ()가있는 객체의 페이지 목록을 반환하려고 시도하지만 문자열 이름을 사용하여 테이블에 가입하는 방법을 알지 못합니다.

현재 페이지에 대해 10 개의 개체를 반환 할 때 11 개의 쿼리를 수행합니다. 1을 사용하여 10 개의 오브젝트를 가져오고 각 오브젝트에 대해 1을 사용하여 ObjectType에 따라 관련 데이터를 테이블에서 가져옵니다. 약 3 초가 걸리는 반면 1 회의 쿼리에는 약 200ms가 소요됩니다. 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

기본적으로 사용자 지정 식별자가있는 TPT 계층 구조가 있지만 C# 모델 클래스의 형식 계층 구조로 모델링되지 않았습니다? – grek40

+0

'Type'이 다른 경우 관련된 모든 테이블에서 'Unid'가 고유하거나 다른 항목에 동일한 'Unid'값이 있습니까? – grek40

+0

첫 번째 코멘트에서 무엇을 말했는지는 알지 못합니다.하지만 아마도 이것이 내가 가진 것입니다. Unid는 객체의 Unid입니다. 동일한 Unid가 '형식 테이블'에 있습니다. 예를 들어 unid를 선택하고 object => {guid : 3F2504E0-4F89-11D3-9A0C-0305E82C3301을 입력하고 'VRIJ1OBJECT'를 입력 한 다음 vrij1objecten에서 관련 데이터를 선택합니다. 여기서 objectunid = '3F2504E0-4F89-11D3-9A0C-0305E82C3301'=> 이것은 객체에 대한 올바른 관련 데이터를 반환합니다. – AppSum

답변

0

당신은, 각각의 가능한 반환 유형 LEFT OUTER JOIN와 쿼리를 만들 각 유형에 대한 결과 개체를 저장하고 IVrijobject에 캐스팅하여 데이터 클라이언트 측을 압축 할 수 있습니다.

:

2 개 종류 (참고 내가 EF6 그것을 만든, 그래서 EF 코어에 필요한 약간의 변화가있을 수 있습니다)

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이 필요하지 않습니다.

+0

* "[...]은 1 개의 쿼리가 약 200ms 만 걸리는 반면 *"200ms 쿼리를 볼 수 있다면 EF에서 더 나은 쿼리를 디자인하는 방법에 대한 힌트 일 수 있습니다. – grek40