我在连接已读过的许多帖子时遇到了麻烦(意识到我可能需要购买Eric Evans的书,而不是依靠大量的互联网资料),我试图坚持领域驱动的设计,但是却遇到了麻烦将数据保存回数据库之前,最好的方法是从表示层到域的通信。为简单起见,现在我有一个可以包含作业列表的用户类。当用户打开应用程序时,将查询其活动目录信息,并且只要他们打开了该应用程序,便会使用其数据填充此类。然后,用户可以编辑现有作业(如果拥有)或创建一个新作业。我开始创建一个使用UnitOfWork类的服务类,以为这将成为我的交流,但这就是我的绊脚石。
当前设置:
DAL-EF 6生成的POCO和DbContext,存储库,工作单元
域-实体,存储库和工作单元接口,域接口服务我在本文中指的是?
演示-MVC(内部网),具体服务?
问题:
服务类是实现此类通信(以及创建域类的新实例(例如,创建新作业的方法))的最佳实现类吗?我意识到我可以使用工厂模式,但是我不想变得太复杂了吗?该服务将驻留在域层中还是为应用程序层创建一个单独的项目?然后,接口会进入域层,而具体实现会进入应用层吗?我觉得那可能会使应用复杂化。另外,服务是WCF还是我可以只创建自己的类?
如何使用此服务将MVC层中的ViewModel映射回域(如果那是最好的方法),而不会将表示层泄漏到服务中?我已经阅读了DTO,但是那在服务层上是不是太过分了?还是可以将我的域实体公开为ViewModel?我一定在想这个错误。我无法想象在没有任何泄漏的情况下这种交互在控制器中的外观。对不起所有问题,谢谢。
public class User
{
public int Id{ get; set; }
public string WindowsId{ get; private set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName { get { return FirstName + " " + LastName; } }
public string Email { get; set; }
public string WorkPhone { get; set; }
public List<Job> Jobs { get; private set; }
public void AddJob(Job job)
{
if(job == null)
throw new Exception("Job is null");
var newJob = new Job(this) //tell the job that this user is creating the job
{
Description = job.Description,
DueDate = job.DueDate,
Name = job.Name,
Reason = job.Reason
};
Jobs.Add(newJob);
}
}
更新:我的解决方案
我最终从每个人的答案中得到了一点点。
@granadaCoder-我将我的EF POCO用作传递给DTO的类,因为大多数时候,这就是我在ViewModel中向用户显示的数据。因此,它允许我将DTO用作ViewModels
@ChrisPratt-你是正确的。这样做避免了很多额外的工作。我所做的就是创建一个包含我需要的所有查询的服务。而且,即使我不得不更改EF,它也不会打扰我的其他层。我要做的就是创建存储库和UOW
@MilivojMilani-我的确在控制器中有重复的逻辑,因此服务层使我与DRY主体保持一致
@Yorro-因为我仍然不确定服务层的设置,因此我使用了您的观点和参考来加强设计。由于这是一个较小的项目,因此我使用创建的服务和接口设置了另一个文件夹,没有WCF
最佳答案
如果使用的是Entity Framework,请远离存储库/工作单元模式。 EF本身就是这种模式的实现。如果要抽象Entity Framework,则可以实现一种服务模式,该模式将完全烘焙的数据完全按您的需要返回。最好用一个例子说明:
带有EF /存储库
IQueryable<Post> posts = db.Posts.Where(m => m.BlogId == blog.Id && m.Status == PostStatuses.Published && m.PublishDate <= DateTime.Now).OrderBy(m => m.PublishDate);
有服务
List<Post> posts = service.GetPublishedPostsForBlog(blog);
这里的两个主要区别是:
您将返回已经通过服务从数据库中提取的数据;存储库/ EF将返回一个可能已针对数据库执行的可查询对象。
您所有的逻辑都会与服务一起进入服务方法。而使用存储库/ EF可以就地构建查询。
就是说,不要挂在应用程序的各个层面上。这不是关于您拥有多少层以及如何称呼它们,而是关于将逻辑从应用程序的各个部分中抽象出来,这些部分不需要知道如何构造该逻辑。例如,返回发布的博客文章列表的控制器操作就不需要知道什么使文章被“发布”。那是应该放在其他地方的域逻辑(例如返回此数据集的服务方法)。这个想法只是遵循单一职责原则:类/方法/等。应该做一件事并做好。您的控制器动作只应与返回视图有关(并做最少的工作来获取该视图所需的内容)。
就映射而言,该术语准确地解释了您的操作,因此,我不确定这里的混乱之处。例如,如果要将
Post
映射到PostViewModel
:var model = new PostViewModel
{
Title = post.Title,
Content = post.Content,
...
}
或使用对象列表,可以使用LINQ:
var model = posts.Select(m => new PostViewModel
{
Title = m.Title,
Content = m.Content,
...
}
如果您的问题很简单:我如何更轻松地做到这一点?然后,您可以查看第三方映射库,例如AutoMapper。