当前位置: 首页 > 知识库问答 >
问题:

洋葱架构中视图模型/DTO的放置

微生慈
2023-03-14

我目前正在重构ASP。NET MVC项目中使用了洋葱结构,因为它似乎适合未来发展的需要。

我已经设置了我认为需要使用的层,现在我的解决方案如下所示:

所以,基本上正如我所理解的,ClientName。核心项目根本不应该引用其他项目。客户端名称。基础架构应引用客户端名称。核心 。ClientName上的Interfaces文件夹。核心定义客户端名称中的服务。基础架构、my DbContext和域实体是分开的,因此只有这些实体在核心项目中。

我一头撞在墙上的地方是,ClientName。基础设施项目不应该将域实体返回给html" target="_blank">调用它的任何客户端。这将在核心项目和任何“违反”洋葱原则的UI之间创建一个引用。正如我所读到的,解决这个问题的一种方法是让基础设施服务返回DTO。但是,如果我从个性化服务类返回个性化Dto个性化Dto对象需要由ClientName. Core项目知道,因为那是接口所在的位置。

所以问题是:我到底把用于UI/客户端的DTO/ViewModel/其他模型放在哪里?我是否创建了一个单独的类库来保存这些模型并让UI、基础设施和核心项目都引用它?

非常感谢任何帮助/提示,因为我对此有点困惑;-)

提前谢谢。

编辑

基于欣快的回答,我在这里编写示例代码,只是为了检查我是否正确,也许还有一些后续问题。

所以基本上,在我的ClientName中。核心层,我有包含业务逻辑的实体,即个人和公司实体可以如下所示:

(Exists in ClientName.Core/Entities)
public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }   
    public Firm Firm { get; set; }
}

(Exists in ClientName.Core/Entities)
Public class Firm
{
    public int Id { get; set; }
    public string Name { get; set; }
    public IEnumerable<Person> Employees { get; set; }

    public IEnumerable<Person> GetEmployeesByName(string name)
    {
        return Employees.Where(x => x.Name.Equals(name));
    }

    public void AddEmployee(Person employee)
    {
        Employees.Add(employee);
    } 

    public void CreateFirm(Firm firm)
    {
        // what should happen here? Using entity framework, I have no reference to the DbContext here...
    }
}

(Exists in ClientName.Infrastructure/Services)
public class FirmService : IFirmService
{
    private readonly IDbContext _context;

    public FirmService(IDbContext context)
    {
        _context = context;
    } 

    public Firm GetById(int firmId)
    {
        return _context.Firms.Find(firmId);
    } 

    // So basically, this should not call any domain business logic?
    public void CreateFirm(CreateFirmFormViewModel formViewModel)
    {
        Firm firm = new Firm()
        {
           Name = formViewModel.Name;
        } 

        _context.Firms.Add(firm);
        _context.SaveChanges();
    } 

    public IEnumerable<Person> GetEmployeesByName(int firmId, string name)
    {
        Firm firm = _context.Firms.Find(firmId);
        return firm.GetEmployeesByName(name);
    }
}

每个读取查询都应该直接在实体上定义(因为我使用的是实体框架,所以可能是实体扩展),并且任何创建/更新/删除都只能在基础架构层的服务中发生,这对吗?

应读取(即<代码>IEnumerable

再次感谢:-)

共有1个答案

呼延鸿畅
2023-03-14

首先,您不是从个性化服务返回Person,而是从IPERService返回Person。这是巨大的概念差异。个性化服务只实现IPERService定义的内容。它不在乎它使用什么接口或对象。

简而言之,Core项目应该包含业务实体中的所有业务逻辑。如果您没有任何实际逻辑,那将只是普通的DTO。然后,基础设施将负责从数据库中保存/加载这些实体。如果它使用自己的实体创建自己的模型,或者如果它重用core定义的模型,则是基础设施的实现细节。同时,UI(或Web)项目将与Core项目中的实体一起工作,但它不会关心持久性是如何发生的。它只想“做生意”。

这里的关键点是Core(或业务逻辑)是可自动测试的,不涉及UI或数据库代码。只要您能够实现这一点,一些DTO在哪里并不重要。

编辑:

这开始变得困难起来。您遇到了相互冲突的设计要求。一方面,您有明确的域设计。另一方面,您希望您的模型能够使用EF持久化。有一点很清楚:您将妥协并扭曲您的域模型,以便它可以在EF中使用。

现在谈谈具体问题。第一个是创建公司。在这里,您在域所理解的“新公司”之间存在冲突。确保新公司的名称有效。另一方面,您希望创建实例并让EF知道它。我要做的方法是从类中删除创建公司,并在IFirmService中更改创建公司,这样它只接受创建新公司所需的参数(例如,只接受名称),然后返回新创建的公司。此外,存储库不应该调用域的想法是错误的。例如,存储库可能会调用域来验证它创建的公司是否有效,如果无效,则不要将其添加到EF中。

我看到的第二个问题是在公司中保留员工集合。虽然这对域来说很好,但对持久性来说却是灾难(除非您认为在这种情况下延迟加载是可以的)。再一次如何满足“公司拥有员工集合”的领域需求以及将实体持久化到数据库中的能力,没有简单的方法。第一种选择是不使用此集合并将其移动到IFirmService,在那里可以正确地实现它。第三种选择是最极端的。也就是说,在使所有“get”都成为抽象方法的同时,使其成为一个抽象类,在基础设施项目中创建其实现,并使用具体实例所具有的EF上下文实现get方法。此外,只有在基础设施中创建了具体的公司实例,这才有可能实现,这就是我上面所建议的。

我个人喜欢第三种选择,因为它保持了方法的良好性和内聚性。但一些EF纯粹主义者可能不同意我的观点。

 类似资料:
  • 洋葱圈模型 我们把函数从内向外组合,把内层函数的执行控制权包裹成next参数传递给外层函数,让外层函数自行控制内层函数执行时机,我们再一次把控制流暴露出来,第一次是引入continuation,把return决定的控制流暴露到参数中。 于是 我们可以在外层函数 执行next的前后加入自己的逻辑,得到 AOP 的before与after语义,但不仅仅如此,我们甚至可以不执行内层函数,然后我们穿越地心

  • 我一直在阅读洋葱架构,今天我发现了鲍勃叔叔的清洁架构。 对于我来说,我看不出它们之间有什么不同,它们看起来完全一样(除了命名惯例)。 干杯

  • 本文向大家介绍说说koa洋葱模型有什么优点?它是如何实现洋葱模型的?相关面试题,主要包含被问及说说koa洋葱模型有什么优点?它是如何实现洋葱模型的?时的应答技巧和注意事项,需要的朋友参考一下 koa洋葱模型可以将中间件级联执行,由用户决定是否向下级中间件执行。 在koa中维护了一个数组用来保存中间件,在开启http服务器时,使用compose方法将中间件级联,取出数组中第一个执行,并返回Promi

  • 使用Spring MVC,我们通常会看到控制器、服务和存储库层。仓库层使用实体模型,实体模型与数据库是一对一的映射。我想过跟着- 服务层应该使用相同的实体模型吗? 服务层应该使用单独的域模型吗?如果是,那么到/到来回映射应该在服务层完成? 控制器层我们应该使用相同的域模型吗? 控制器层应该使用单独的DTO模型吗?如果是,那么到/来回映射应该在控制器层完成? 我们有什么简单的方法可以在不写太多冗长代

  • 我一直在研究和实现洋葱架构模式(http://jeffreypalermo.com/blog/the-onion-architecture-part-3/)。 让我质疑我理解是否正确的一件事是: