在将对象保存到持久性存储时,只是试图了解服务层和存储库层的职责.
我目前的立场是这样的:
在我的控制器中,我根据用户提交的数据(从表单中)创建了一个"Note"对象.然后用户在"NoteService"上调用"Save"(通过依赖注入存在).
在"NoteService"的"Save"方法中,我执行业务逻辑验证,然后将"Note"对象传递给"NoteRepository"的"Save"方法.
在"NoteRepository"的"保存"方法,然后进行检查,看是否有这个对象上现有的主键,如果是的话得到从数据库,它是使用"注意"对象通过传递的属性更新对象和它然后保存回到db.如果没有主键,则将对象简单地保存到数据库,然后使用新创建的主键返回到服务.
我一直在阅读有关DDD的信息,我认为我可能错误地使用了服务,或者至少以不那么理想的方式使用服务.我的服务类往往有很多包含存储库引用的实例变量,它们似乎做了很多工作(即有很多方法).
是否可以创建更有针对性的服务?像每个服务执行某些特定逻辑的方法一样?此外,服务类应该将实例变量存储到其他实体吗?我读到了一些关于无状态服务的内容,我不确定是否通过使用这些实例变量来破坏该规则.
谢谢!
我正在努力转换SoapUI TestRunner的Ant执行以使用maven插件,我无法得到关于如何使用此插件执行多个项目的良好答案.
我在2010年的Smartbear论坛上发现了一个论坛帖子,列出了一些方法,但似乎没有一个方法可行(编写一些脚本来调用具有不同参数的maven或为每个项目添加执行).
有没有最好的解决方法?或者有没有人看到这个问题的创造性解决方案?
我猜这是一个大规模的问题......
这是我提到的帖子.
这个问题源自我在Grails应用程序上的工作,但它适用于几乎所有在层中开发的Web应用程序.这是一个简单的例子:
class OrderService {
// Option 1
def shipOrder(Order order) {
order.status = OrderStatus.SHIPPED
emailService.sendShipmentEmail(order)
// ...
}
// Option 2
def shipOrder(long orderId) {
def order = Order.get(orderId)
order.status = OrderStatus.SHIPPED
emailService.sendShipmentEmail(order)
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
这些选项中的任何一个都记录为比另一个更好吗?
grails design-patterns web-applications code-design service-layer
在Eric Evan的书"领域驱动设计"(人们通常称之为'DDD的最佳示例')中,有很多聚合根(大多数是域模型甚至实体)的例子都满足了某个请求.
我们来看下面的例子:
public Car : IAggregateRoot {
public List<Wheel> Wheels { get; set; }
public void ReplaceWheels();
}
Run Code Online (Sandbox Code Playgroud)
为了更换车轮,我必须从GarageService请求一组新的车轮,车轮本身从WheelRepository收集车轮.在一个场景中,我不是客户,而是替换车轮的车库所有者/机械师,所以打电话很自然:
myCar.ReplaceWheels();
// I'm a domain expert! I have the capabilities to replace the wheels
Run Code Online (Sandbox Code Playgroud)
我的问题是:将WheelService作为聚合根的依赖注入是否正确?或者我应该更好地谈谈WheelService?
public class MyCar : IAggregateRoot {
private readonly IWheelService _wheelService;
public List<Wheel> Wheels { get; set; }
public MyCar(IWheelService wheelService) {
this._wheelService = wheelService;
}
public void ReplaceWheels() {
this.Wheels = _wheelService.getNewSet();
}
}
Run Code Online (Sandbox Code Playgroud)
要么
myWheelService.getNewSet(Car car);
Run Code Online (Sandbox Code Playgroud) 在我的ASP.net mvc应用程序中,我使用服务层和存储库来保持我的控制器很薄.典型的详细信息只读视图如下所示:
public ActionResult Details(int id)
{
var project = _projectService.GetById(id);
return View(Mapper.Map<Project, ProjectDetails>(project));
}
Run Code Online (Sandbox Code Playgroud)
服务层:
public class ProjectService : IProjectService
{
public Project GetById(int id)
{
var project = _projectRepository.GetProject(id);
// do some stuff
return project;
}
}
public class ProjectRepository : IProjectRepository
{
public Project GetProject(int id)
{
return context.Projects.Find(id);
}
}
Run Code Online (Sandbox Code Playgroud)
从服务层移动到视图模型非常容易,因为自动化器可以很容易地平整事物.从视图模型直接移动另一个传递到我的服务层是我努力想出一个好的解决方案的地方.
在像Create一样的情况下,有什么好办法呢?
[HttpPost]
public ActionResult Create(CreateProjectViewModel model)
{
if(!ModelState.IsValid)
{
return View(model);
}
// TODO
return RedirectToAction("Index");
}
Run Code Online (Sandbox Code Playgroud)
我很确定服务层不应该对视图模型有任何了解,但我也不认为AutoMapper在这种情况下运行良好,因为它不擅长采用扁平模型并将其变成复杂对象.
我的控制器应该如何与服务层通信?我想尽可能保持控制器中的代码.
我们最近开始使用Doctrine 2.2和Zend Framework 2的一部分来改进组织,减少重复等.今天,我开始提出实现服务层的想法,作为我们的控制器和Doctrine实体之间的中介.
现在,我们的大部分逻辑都存在于控制器中.另外,我们使用动作助手来测试某些权限; 然而,在实施Zend\Di后我想出了一种新的方法.我开始创建特定于实体的服务模型,它使用Zend\Di注入EntityManager实例,以及当前用户的权限.
控制器代码如下:
class Project_DeleteController extends Webjawns_Controller_Action
{
public function init()
{
$this->_initJsonContext();
}
public function indexAction()
{
$response = $this->_getAjaxResponse();
$auditId = (int) $this->_getParam('audit_id');
if (!$auditId) {
throw new DomainException('Audit ID required');
}
/* @var $auditService Service\Audit */
$auditService = $this->getDependencyInjector()->get('Service\Audit');
try {
$auditService->delete($auditId);
$response->setStatusSuccess();
} catch (Webjawns\Exception\SecurityException $e) {
$this->_noAuth();
} catch (Webjawns\Exception\Exception $e) {
$response->setStatusFailure($e->getMessage());
}
$response->sendResponse();
}
}
Run Code Online (Sandbox Code Playgroud)
以及我们的一个服务层的示例.构造函数有两个参数 - 一个是EntityManager,另一个是Entity\UserAccess对象 - 由Zend\Di注入.
namespace Service;
use Webjawns\Service\Doctrine,
Webjawns\Exception;
class Audit extends AbstractService …Run Code Online (Sandbox Code Playgroud) php model-view-controller service-layer doctrine-orm zend-framework2
我已经开发了我的第一个大型(对我来说)MVC项目,现在已经有几个月了,事情变得非常难以导航.
我一直在摒弃重构,并且正在寻求"最佳实践"的现代示例,只要保持控制器的精简并将所有数据移动到模型中.
我读过这篇文章详细讨论了一些内容,但没有提供示例项目.
这里发布的大多数"最佳实践"主题都倾向于链接到MVC音乐商店或Nerd Dinner项目,但与此同时,评论倾向于说他们更多是"初学者指南",而不是"最佳实践"的例子.
有谁知道任何展示适当开发结构的最新开源MVC项目?
注意:我想学习解决的一个典型问题:我的控制器很长并且充满了驱动网站的代码 - 我需要将这些代码移到仅由控制器引用的方法中.我在哪里抛出所有这些方法?
下面是一个来自控制器的代码示例,如其中一个回复的评论所示.我如何将这些信息移到我的ViewModel上?(我在下面包含了ViewModel):
控制器:
public ActionResult AttendanceView(int id)
{
//
// Generates list of Attendances specifically for current Course
var attendanceItems = db.Attendance.Where(s => s.CourseID == id);
List<Attendance> attendanceItemsList = attendanceItems.ToList();
// End of generating list of Attendances
//
// Generates list of Students in alphabetical order sorted by LastName
var student = attendanceItemsList.Select(a => a.Student).Distinct().OrderBy(s => s.LastName);
List<Student> StudentList = student.ToList();
// End of generating list of Students
//
// …Run Code Online (Sandbox Code Playgroud) 我有点厌倦了编写这样的服务层代码:
下面的代码只是读者的一个例子.所以他们可能有错误或错别字,抱歉:)
//ViewModel
public class EntityIndexFilterPartial
{
public int? Id { get; set; }
public DateTime? StartDate { get; set; }
public DateTime? EndDate { get; set; }
public IEnumerable<SelectListItem> StatusList { get; set; }
public int? StatusID { get; set; }
}
//Service Layer method
//Method parameters are reperesents view model properties
public IQueryable<Entity> FilterBy(int? id, DateTime? startDate, DateTime? endDate, int? statusId)
{
var filter = _db.Entities.AsQueryable();
if (id.HasValue)
filter = filter.Where(x => x.Id == id.Value);
if (startDate.HasValue)
filter …Run Code Online (Sandbox Code Playgroud) 顾名思义,设计服务层时的最佳实践是什么?我确实知道服务层应始终返回DTO,以便将域(实体)对象保留在服务层内。但是,控制器对服务层的输入应该是什么?
我在下面提出了三个建议:
方法1:在这种方法中,域对象(项)保留在服务层中。
class Controller
{
@Autowired
private ItemService service;
public ItemDTO createItem(IntemDTO dto)
{
// service layer returns a DTO object and accepts a DTO object
return service.createItem(dto);
}
}
Run Code Online (Sandbox Code Playgroud)
方法2:这是服务层接收自定义请求对象的地方。我已经在AWS Java SDK和Google Cloud Java API中广泛地看到了这种模式
class Controller
{
@Autowired
private ItemService service;
public ItemDTO createItem(CreateItemRequest request)
{
// service layer returns a DTO object and accepts a custom request object
return service.createItem(request);
}
}
Run Code Online (Sandbox Code Playgroud)
方法3:服务层接受DTO并返回域对象。我不喜欢这种方法。但是它已在我的工作场所中广泛使用。
class Controller
{
@Autowired
private ItemService service;
public ItemDTO createItem(CreateItemRequest request)
{
// …Run Code Online (Sandbox Code Playgroud) service-layer ×10
c# ×4
asp.net-mvc ×3
code-design ×1
controller ×1
doctrine-orm ×1
dto ×1
grails ×1
linq ×1
maven-plugin ×1
php ×1
repository ×1
rest ×1
soapui ×1