2017-04-04 58 views
0

目前我知道,對於MVC應用程序,視圖應該由ViewModel填充,控制器應該保持苗條,並且您不應該直接將實體框架實體直接暴露給控制器。對於一個小的MVC應用程序,你如何填充DTO和ViewModels?

在哪裏我陷入困境,是在哪裏把模型(從數據庫)的功能,並將其轉換爲ViewModel數據。

此刻我有一個實體表示數據庫中的一系列任務。這是該類:

public class Task 
    { 
     public int ID { get; set; } 
     public string Name { get; set; } 
     public Contact Contact { get; set; } 
     public string Description { get; set; } 
     public DateTime DateCreated { get; set; } 
     public DateTime DateModified { get; set; } 
     public int? QuotedHours { get; set; } 
     public int? UsedHours { get; set; } 
     public virtual ICollection<Attachment> Attachments { get; set; } 
     public virtual ICollection<Comment> Comments { get; set; } 
     public virtual Status Status { get; set; } 
     public int RecoveryStatusID { get; set; } 
     public virtual RecoveryStatus RecoveryStatus { get; set; } 
    } 

我有一個DTO類看起來完全一樣,但使用列表而不是虛擬ICollections。它看起來像這樣:

public class Task 
    { 
     public int ID { get; set; } 
     public string Name { get; set; } 
     public Contact Contact { get; set; } 
     public string Description { get; set; } 
     public DateTime DateCreated { get; set; } 
     public DateTime DateModified { get; set; } 
     public int? QuotedHours { get; set; } 
     public int? UsedHours { get; set; } 
     public List<Attachment> Attachments { get; set; } 
     public List<Comment> Comments { get; set; } 
     public virtual Status Status { get; set; } 
     public int RecoveryStatusID { get; set; } 
     public RecoveryStatus RecoveryStatus { get; set; } 
    } 

然後,我有,我想填充視圖模型。

public class TaskIndexViewModel 
    { 
     public string CategoryName { get; set; } 
     public List<DTO.Task> Tasks { get; set; } 
    } 

所以:

  • 如何映射EF實體到DTO?我認爲它涉及使用Linq Select語句。我非常喜歡使用像AutoMapper這樣的東西,但我無法圍繞它的工作方式包裝頭(很多文檔已過時,似乎主要關注舊的靜態實現,顯然它已更新爲基於實例執行?)

  • 一旦我在DTO中有數據,那麼翻譯從DTO到哪裏進入TaskIndexViewModel類?我知道這將涉及Linq GroupBy聲明,還有Select語句將它放入一個新List中,但這種邏輯應該放在哪裏?我想創建一個新的服務文件夾,並把這種功能放在那裏,但我覺得髒在控制器中實例化新對象,然後調用這個新類的函數。除非這不是一件壞事?

任何幫助,將不勝感激:)

+0

爲什麼你需要有一個DTO和一個實體類?他們可以很容易地相同...您當前的實體類也可以用作DTO。 – raykrow

+0

我認爲這是糟糕的形式,直接傳遞實體到視圖?由於EF延遲加載並最終產生了EF代理......(我可能有一些單詞錯誤) –

+0

您的權利是您不想將原始實體類傳遞給視圖,但這就是爲什麼您在它們進入視圖之前將它們映射到視圖模型。我不認爲單獨的DTO和實體類是'錯誤',但我認爲這是不必要的。 – raykrow

回答

1

查看此博客文章中,我提出

http://krow.tech/posts/Essentials-of-AutoMapper

(我要嘲笑這裏的一些代碼)

var db = new MyEfContext(); // Or however you create or get your ef context IoC maybe? 

IEnumerable<Task> tasks = db.Tasks 
    .Select(e => Mapper.Map<DTO.Task>(e)); 

var vm = new TaskIndexViewModel 
{ 
    Tasks = tasks, 
    CategoryName = "This Cool Cat" 
}; 

有了這個,你可以將你的任務實體映射到你的任務DTO。您的映射可能看起來像......

config.CreateMap<Task, DTO.Task>() 
    .ForMember(dest => dest.Attachments.ToList(), opt => opt.MapFrom(src => src.Attachments)) 

然而,鑑於你的實體和DTO的名稱是相同的,你可能會更好寫一些TypeResolvers(見上文鏈接)AutoMapper轉產ICollectionIList然後使用只需告訴AutoMapper:

config.CreateMap<Task, DTO.Task>(); 

我希望能回答你的問題。正如我們在評論中談到的,我仍然認爲映射到指定的DTO是過分的,即使在這種情況下,您將實體直接傳遞給虛擬機(任何人都可以隨時糾正我)。我只是想:

var vm = new TaskIndexViewModel 
{ 
    Tasks = db.Tasks.ToList(), 
    CategoryName = "This Cool Cat" 
}; 

如果需要,請參閱上面鏈接的文章以獲取更多上下文。

0

我不同意@ raykrow的答案的最後一節。這種結構:

var vm = new TaskIndexViewModel 
{ 
    Tasks = db.Tasks.ToList(), 
    CategoryName = "This Cool Cat" 
}; 

...在Tasks視圖模型屬性結果變得緊密結合到EF實體它做一個.ToList()。如果您決定從EF切換到另一個ORM,會發生什麼?

擁有與域類(甚至)相同的視圖模型仍然是有益的。至於如何輕鬆地將模型的結果映射到您的視圖模型,這就是爲什麼像AutoMapper這樣的圖書館存在的原因。沒有AutoMapper:

// tasks becomes an IEnumerable<TaskViewModel> 
var tasks = db.Tasks.Select(x => new TaskViewModel { A = x.A, B = x.B }).ToList(); 

var vm = new TaskIndexViewModel 
{ 
    Tasks = tasks, 
    Foo = bar 
}; 
+0

這是一個偉大的觀點。切換ORM會導致一個真正的問題。在設計時要考慮一些需要考慮的事項 – raykrow

0

我使用AutoMapper,它是一個很容易和方便的方法來映射很多類在一起。

Mapper.CreateMap<Task, DTO.Task>() 
    .ForMember(dest => dest.Attachments, opt => opt.MapFrom(src => src.ToList<Attachment>()) 
    .ForMember(dest => dest.Comments, opt => opt.MapFrom(src => src.ToList<Comment>()) 
    .ReverseMap() 
    .ForMember(dest => dest.Attachments, opt => opt.MapFrom(src => src as ICollection<Attachment>) 
    .ForMember(dest => dest.Comments, opt => opt.MapFrom(src => src as ICollection<Comment>); 

現在你可以說

var taskDto = Mapper.Map<Task, DTO.Task>(task); 

但reversemap部分也可以讓你做反向也是如此。

var task = Mapper.Map<DTO.Task, Task>(taskDto); 

理想情況下,您會希望將您的映射放入配置文件中。

此外,不創建DTOs沒有傷害。如果您決定不創建DTO,那麼您將控制器綁定到您的實體,並且在一個小型應用程序中,這可能永遠不會成爲問題,但如果應用程序不斷增長,您可能會發現實施不同邏輯可能會變得困難,並且您可能會被迫在控制器中放入一些技術上不屬於此處的東西。所以如果你決定不使用DTO,你應該確定應用程序將保持很小。

相關問題