簡體   English   中英

我如何首先使用可重用的查詢/表達式和EF代碼在父級中獲取子實體作為DTO?

[英]How can I fetch child entities as DTO in parent using reusable queries/Expression's with EF code first?

我在尋找將實體及其子實體轉換為DTO對象的好方法時遇到問題。 在本文中,我創建了偽代碼,這是一個簡化的示例,省略了數據庫上下文DTO對象。 假設我有一個父實體和一個子實體:

public class Parent {
    int Id;
    string Name;
    List<Child> Children;
}

public class Child {
    int Id;
    string Name;
    Parent Parent;
    int ParentId;
}

我研究了兩種可能性,但我一直找不到一個好的解決方案。 請查看兩個示例以及我遇到的問題。

1.使用選擇查詢的示例

要檢索所有父實體作為DTO,可以在Controller中執行以下操作:

public IHttpActionResult GetParents()
{
    var children = from c in _context.Children
    select new ChildDTO()
    {
        Id = c.Id,
        Name= c.Name
    };

    var parents = from p in _context.Parents
    select new ParentDTO()
    {
        Id = p.Id,
        Name = p.Name       
        Children = children.ToList(),
    };

    return parents;
}

這將返回父DTO對象及其所有子對象作為DTO對象。 如果我想創建一個新函數以僅獲取ID為'1'的Parent,那么我現在必須復制select語句以添加where子句:

public IHttpActionResult GetParent(int parentId)
{
    var parents = from p in _context.Parents where p.id == parentId
...

在某些情況下,如果我只想顯示父母列表,我也不想讓孩子反對。 這意味着我基本上必須復制代碼並將選擇內容更改為此:

select new ParentDTO()
{
    Id = p.Id,
    Name = p.Name       
    //Removed the Children
    //Children = children.ToList(), 
};

在此示例中,我沒有看到一種盡可能多地重用代碼的好方法,因此,我最終不會一遍又一遍地編寫相同的基本select語句。

2.使用表達式的示例

我也可以為父母和孩子創建表達式,但是我不知道

private static readonly Expression<Func<Child, ChildDTO>> AsChildDTO =
p => new ChildDTO()
{
    Id = p.Id,
    Name = p.Name
};

private static readonly Expression<Func<Parent, ParentDTO>> AsParentDTO =
p => new ParentDTO()
{
    Id = p.Id,
    Name = p.Name
};

為了得到父母,我可以在控制器中執行以下操作:

...
//Get list of parents
var parents = _context.Parents.Select(AsParentDTO);

//Or: Get only parent with Id
var specificParent= _context.Parents
.Select(AsParentDTO)
.Where(p => p.Id == 1);

return parents;
...

這個解決方案對我來說似乎很好,因為我可以重復使用Epressions並根據需要擴展它們。 我似乎只能通過這種方式將孩子包括在父母中:

...
var parents = _context.Parents
.Include(p => p.Children)
//I have no idea if it is possible to Invoke the child Expression here...
.Select(p => p.Children= AsChildDTO.Invoke()) //<-- this does not work
.Select(AsParentDTO)
...

正如我在上面的評論中所寫; 我不知道是否有可能在這里調用子表達式。

結尾

這是我嘗試過但仍然堅持的兩件事。 但是也可能是我錯過了一個非常明顯的解決方案。 我的問題是,如何以可以重用盡可能多的代碼的方式解決此問題?

我認為您過於復雜了。

var results=_context.Parents
  .Include(p=>p.Children);

將返回您的EF對象。 那就是你應該使用的。 如果要將EF對象轉換為DTO對象,請將其保存為最終投影(我很少使用DTO對象,因為來自EF的POCO對象通常就可以了)。

var parents=results.Select(p=>new ParentDTO
  { id=p.id,name=p.name,children=p.Children.ToList()}
);

如果只需要父母1,則:

var parent=results.Where(p=>p.id==1);

如果您希望將其作為parentDTO:

var parent=results.Where(p=>p.id==1).Select(p=>new ParentDTO {
  { id=p.id,name=p.name,children=p.Children.ToList()}
);

您可以使用AsParentDto之類的東西,但這是否意味着您將要復制整個Parent屬性? (在您的簡單情況下-ID和名稱)。 並且,如果要復制整個屬性列表,為什么要創建一個具有與EF對象相同的屬性的新對象,而不僅僅是重用EF對象? 我唯一使用Dto對象的情況是,如果我想傳遞僅具有某些屬性的父對象,並且希望避免自己從數據庫中檢索其他屬性,在這種情況下,我仍然會使用原始數據庫查詢,然后將其投影到最后一步。

var slimparent=results.Where(p=>p.id==1).Select(p=>new SlimParentDto {
  id=p.id });

當然,如果我想要的只是父ID,那么我將使用甚至更簡單的IQueryable<int>

var parentids=results.Where(p=>p.id==1).Select(p=>p.id);

-TL; DR-

創建單個方法來檢索您的對象將包括的所有屬性。 然后,所有內容都應以此為基礎,並在控制器中附加進一步的細化以將其過濾為僅所需的數據子集。 然后,作為最后一步,將結果投影到所需的任何DTO中。 在完成投影之前,切勿使用任何方法來枚舉IQueryable。 EF / LINQ隨后將為您生成最佳查詢,只需檢索填充DTO所需的屬性即可。

暫無
暫無

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

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