2016-05-27 66 views
0

使用實體框架和DTO的最佳方式是什麼?ASP.NET MVC實體框架中的DTO的最佳實踐

假設映射後我有這樣的對象:

Author 
    int id 
    sting name 
    List<Book> books 

Book 
    int id 
    string name 
    Author author 
    int authorID 

我的DTO

AuthorDTO 
    int id 
    sting name 

BookDTO 
    int id 
    string name 
    int authorID 

由於作者可以有很多的書,我不希望檢索所有的人時,例如我只對作者感興趣。

但有時我可能想要得到幾個作者,過濾書籍或所有書籍。 我可以去與多個查詢AuthorDTO GetAuthor(int id)List<BookDTO> GetBooks(int authorID)。但是這意味着要訪問數據庫。

的方法,我看到它:

  1. 如果我在AuthorDTOList<BookDTO> books工作可以做了。但是有時我會保留這個列表爲空,例如我只列出了作者。這意味着一些不一致,混亂和需要記住的許多細節。

  2. 返回Tuple<AuthorDTO, List<BookDTO>>它可能有點混亂。

  3. 定義新的DTO。

    AuthorAndBooksDTO 
        AuthorDTO author 
        List<BookDTO> books 
    
+0

在我的項目我已經結束了,像這樣的DTO:'BookDTO; int id;字符串名稱; int authorID;字符串作者姓名;'最後一個只是爲了視覺信息,它使我從另一個DB往返節省。作爲一個結論,我只是爲每個導航屬性模型添加'string Name'。 – Szer

回答

2

我想澄清所涉及的問題,實際上解決您在這裏混淆。

首先最重要的是,您的實體類 DTO。其實,這是全部是他們是。它們是代表數據庫中表結構的類,以便來自Entity Framework所做查詢的數據可以映射到它們。換句話說,它們是字面上傳輸數據的對象。微軟以及隨後太多的MVC開發者的失敗在於將他們與MVC模式描述的大M模型混爲一談。

因此,使用實體框架返回實體的一個或多個實例,然後在最終在代碼中使用實體框架之前將其映射到另一個DTO類絕對沒有意義。你所做的只是創建一個毫無意義的抽象級別,它不會給你的應用程序增加任何東西,但又需要維護。

至於關係去,這就是實體框架的懶/預先加載進來。爲了充分利用它,雖然,上述相互關係的屬性必須遵循一個非常具體的約定:

public virtual ICollection<Book> Books { get; set; } 

如果將其鍵入List<Book>之類的內容,實體框架根本不會觸及關係。它不會加載相關的實體,並且在將實體保存回數據庫時,它不會持續對該屬性所做的更改。關鍵字virtual允許實體框架動態地爲您的實體創建子類並覆蓋集合屬性以添加延遲加載邏輯。沒有這些,如果您明確使用EF API中的Load,則只會加載相關實體。

假設你的財產是以這種方式定義的,那麼你獲得了一個完整的能力世界。如果你想要所有屬於作者的書,你可以直接與author.Books進行交互(迭代,查詢,等等)。直到你做了一些需要對查詢集進行評估的查詢之後才進行查詢。 EF會根據您要從數據庫請求的信息發出即時查詢。如果你想在您檢索筆者同時裝入所有相關的書籍,你可以用Include與您的查詢:

var author = db.Authors.Include(m => m.Books).SingleOrDefault(m => m.Id == id); 
+0

與新的實體框架核心消除延遲加載這一事實如何做到這一點?另外,要指出數據在數據庫中的存儲方式是視圖想要通過ViewModel讀取數據的方式,這可能會導致問題出現。您可能最終會使用其他自定義DTO,現在您將在ViewModel中同時使用實體和DTO。不是世界的盡頭,但也不是很乾淨。 – David

2

用死守的單層AuthorDTO和選擇性填寫列表中的問題是,你現在被迫跟蹤DTO來自哪裏。書籍列表是否沒有水分,還是這個作者根本沒有書?我是否必須回到我的控制器並調用另一種方法來獲得相同DTO的不同狀態?這從消費者的角度來看缺乏清晰度。

根據我的經驗,我傾向於使用更多的DTO,而不是嘗試重新使用一組基本的DTO來表示多個不同的數據集。它需要更多的「樣板」,不得不在DTO和實體之間建立大量類似的DTO和映射,但最終的特殊性和清晰度使代碼庫更易於閱讀和管理。

1

我的第一個問題是問你爲什麼要創建DTO的第一個地方?另一端是否有消費者使用這些數據?它是一個屏幕?你在建立DTO只是爲了建立DTO的嗎?

既然您將問題標記爲MVC,我將假定您正在將數據發送到視圖。你可能需要一個ViewModel。該ViewModel應該包含使用它的View上顯示的所有數據。然後使用實體框架來填充視圖模型。這可以通過使用投影或一些複雜的單個查詢來完成。

因此,所有這一切都說出來。我會說你想要選項3.

0

就像其他人說的,爲了清晰起見,你應該避免爲特定情況創建「通用」DTO。

當你想有時候有作者和他們的一些書,然後爲它建模一個DTO。 當您只需要作者時,然後創建更適合該作者的另一個DTO。 或者也許你不需要DTO,也許一個包含他們名字的List就足夠了。或者,也許你可以使用匿名類型,如new { AuthorId = author.Id, AuthorName = author.Name }。這取決於實際情況。

如果您使用的是ASP.NET MVC,那麼您將需要的DTO實際上是最能代表您的頁面的ViewModel。

根據你所描述的東西,你的視圖模型可以是這樣的

public class BookViewModel{ 
    public int Id {get;set;} 
    public string Name {get;set;} 
} 
public class AuthorViewModel{ 
    public int Id {get;set;} 
    public string Name {get;set;} 
    public List<BookViewModel> Books {get;set;} = new List<BookViewModel>(); 
} 

public class AuthorsViewModel 
{ 
    public List<AuthorViewModel> Authors {get;set;} = new List<AuthorViewModel>(); 

    //add in this class other properties, like the filters used on the page... 

    public void Load(){ 
     //here you can retrieve the data from your database. 
     //you could do like this: 
     //step 1: retrieve data from DB via EF 
     //step 2: fill in the Authors view models from the data at step 1 
    } 

} 

//and in your controller you're calling the Load method to fill you're viewmodel with data from db. 
public class AuthorsController{ 
    public ActionResult Index(){ 
     AuthorsViewModel model = new AuthorsViewModel(); 
     model.Load(); 
     return View(model); 
    } 
}