簡體   English   中英

將Linq查詢結果映射到DTO類

[英]Mapping Linq Query results to a DTO class

我想使用EF從數據庫中獲取記錄並將值分配給DTO類。請考慮以下表格以獲取Linq查詢。

表A,表B,表C.

對於每個TableA記錄,TableB中有多個記錄。 對於每個TableB記錄,TableC中有多個記錄。 現在我的DTO看起來像這樣

public class TableA_DTO
{
    public int tableA_rowid { get; set; }
    //remaining tableA field definitions

    public List<TableB_DTO> TableB_records { get; set; }
}

public class TableB_DTO
{
    public int tableB_rowid { get; set; }
    //remaining tableB  field definitions

    public List<TableC_DTO> TableC_records { get; set; }
}

public class TableC_DTO
{
    public int tableC_rowid { get; set; }
    //remaining tableC field definitions
}

我的linq查詢看起來像這樣

var qry = from ent in TableA
          select ent;

在我的映射類中,我遍歷查詢結果中的項,如下所示:

    foreach (var dataitem in query)
    {
        TableA_DTO dto = new TableA_DTO();
        dto.tableA_rowid =  dataitem.ID;
        //remaining field definitions here
    }

現在,這適用於TableA中的所有字段,它從數據庫中顯示一條記錄,並在TableA_DTO中為TableA中的每個字段設置所需的屬性。 我還希望在TableA屬性字段中的TableB中填充名稱為TableB_records的所有匹配記錄,並在TableB_DTO中填充TableB_DTO屬性中TableC的所有匹配記錄,名稱為TableC_records

可以這樣做嗎? 我需要改變什么? 是linq查詢還是我的映射方式

謝謝你的時間...

我會將您的DTO從List更改為IEnumerable而不是在LINQ查詢中執行所有操作。

var query = 
    from ent in TableA
    select new TableA_DTO
    {
        TableAProperty = a.Property,
        TableB_records = 
            from b in TableB
            where ent.Key == b.Key
            select new TableB_DTO
            {
                TableBProperty = b.Property,
                TableC_records =
                    from c in TableC
                    where b.Key == c.Key
                    select new TableC_DTO
                    {
                        TableCProperty = c.Property
                    }
            }
    };

首先,我只需要詢問您是否可以使用Entity Framework 4.1和POCO(DbContext)並避免使用DTO的altoghther?

假設答案是否定的,那一定是因為你沒有撤回所有字段,或者你在某種程度上改變了數據的“形狀”。

在這種情況下,您可以將LINQ查詢更改為如下所示:

from t in table
where ...
select new DTOA()
{
  TheDtoProperty = theTableProperty,
  AndSoOn = AndSoOn
};

這樣做的好處是:如果打開SQL事件探查器,您應該看到只有您請求的列才會進入實際的SQL查詢。 如果先查詢全部然后再拉取值,則所有列都將被拉下線。

我會創建一個工廠方法,即: TableA_DTO CreateDTO(TableAItem item);

使用此方法,您可以將查詢重寫為:

IEnumerable<TableA_DTO> = TableA.AsEnumerable().Select(CreateDTO);

這將直接為您提供“DTO”對象的集合。

話雖這么說,如果你正在使用Entity Framework,在這種情況下,在最新版本中添加的EF Code First可能會更有用。

UPDATE

正如其他人所指出的那樣,使用Entity Framework 4.0時不需要展平結果(如下所示),因為它可以將LINQ查詢轉換為有效的展平結果。 因此,僅在使用LINQ to SQL(或可能是其他LINQ提供程序)時才需要以下代碼。 請注意,我僅使用EF over SQL Server而不是Oracle對此進行了測試,因為此行為可能是LINQ提供程序特定的,這意味着Oracle提供程序(仍處於測試階段)或Oracle的商業Devart提供程序仍可以執行N + 1。


你要做的是獲得一組結構像樹的對象。 沒有任何特別注意,您將觸發對數據庫的許多查詢。 使用一級嵌套,您將觸發 N + 1個查詢,但由於您的嵌套深度為兩級,因此您將觸發 M x(N + 1)+ 1個查詢,這幾乎肯定會對性能造成很大影響(無論如何)你的數據集的大小是多少)。 您想要的是確保只有一個查詢發送到數據庫。 為了確保這一點,您必須創建一個中間查詢來展平結果,就像在舊的SQL日期一樣,檢索樹狀數據:-)。 看一下下面的例子:

var records =
    from record in db.TableC
    where ... // any filtering can be done here
    select record;

// important to call ToArray. This ensures that the flatterned result
// is pulled in one single SQL query.
var results = (
    from c in records
    select new
    {
        tableA_rowid = c.B.A.Id,
        tableA_Prop1 = c.B.A.Property1,
        tableA_Prop2 = c.B.A.Property2,
        tableA_PropN = c.B.A.PropertyN,
        tableB_rowid = c.B.Id,
        tableB_Property1 = c.B.Property1,
        tableB_Property2 = c.B.Property2,
        tableB_PropertyN = c.B.PropertyN,
        tableC_rowid = c.Id,
        tableC_Property1 = c.Property1,
        tableC_Property2 = c.Property2,
        tableC_PropertyN = c.PropertyN,
    })
    .ToArray();

下一步是將內存中的數據結構(使用該匿名類型)轉換為DTO對象的樹結構:

// translate the results to DTO tree structure
TableA_DTO[] dtos = (
    from aresult in results
    group aresult by aresult.tableA_rowid into group_a
    let a = group_a.First()
    select new TableA_DTO
    {
        tableA_rowid = a.tableA_rowid,
        tableA_Prop1 = a.tableA_Prop1,
        tableA_Prop2 = a.tableA_Prop2,
        TableB_records = (
            from bresult in group_a
            group bresult by bresult.tableB_rowid into group_b
            let b = group_b.First()
            select new TableB_DTO
            {
                tableB_rowid = b.tableB_rowid,
                tableB_Prop1 = b.tableB_Prop1,
                tableB_Prop2 = b.tableB_Prop2,
                TableC_records = (
                    from c in group_b
                    select new TableC_DTO
                    {
                        tableC_rowid = c.tableC_rowid,
                        tableC_Prop1 = c.tableC_Prop1,
                        tableC_Prop2 = c.tableC_Prop2,
                    }).ToList(),
            }).ToList()
     })
    .ToArray();

正如您所看到的,解決方案的第一部分實際上是執行此操作的“舊”方式,當我們仍然手動編寫SQL查詢時。 不過很好,一旦我們得到這種類型的內存數據,我們可以再次利用LINQ(到Objects)來獲得我們想要的結構中的數據。

請注意,這也允許您進行分頁和排序。 這將有點棘手,但肯定不是不可能的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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