我目前正在重构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
再次感谢:-)
首先,您不是从个性化服务
返回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模型吗?如果是,那么到/来回映射应该在控制器层完成? 我们有什么简单的方法可以在不写太多冗长代
1. 如果测到 bug,开发说不是你怎么办? 2. 如果这个需求,是你自己写的测试用例,你和产品做了评审,开发说还不是,并且这个是你独立完成的,别人不太清楚,这个时候你要怎么做? 3. 如果你现在测试的时候,测试环境没有问题,上线后有问题怎么办? 4. 作为一名测试人员,你是如何看待自己漏侧的问题? 5. 之前写过前端页面吗? 6. 前端界面,有一个button,点击无效,会用什么样的思路去排查?