由于各种原因(关注点分离,性能下降),我想停止向我的视图发送域实体,而改用DTO投影。
我想使用ORM查询创建我的DTO,仅从一个或多个实体中选择我需要的字段。
这样做的正确位置是什么?
我觉得应该有一个集中的位置(类似于实体的存储库)来查询和创建DTO,但是我没有找到这种做法的模式或命名。
我遇到过DTO assembler一词,但看起来这种模式是用于将一个或多个域实体映射到DTO,而在我的情况下,我想跳过加载完整实体并将数据库查询直接转换为DTO。
有这种模式吗?
答案 0 :(得分:0)
您的DTO代表读取模型。为此,我通常使用 query “层”(尽管我倾向于更多地关注问题而不是层)。我通常以与I{Aggregate}Query
相同的方式使用I{Aggregate}Repository
。
接口将以尽可能简单的格式返回数据:
namespace Company.Project.DataAccess
{
public interface ICustomerQuery
{
int CountMatching(Query.Customer.Specification specification);
int Count();
IEnumerable<DataRow> RowsMatching(Query.Customer.Specification specification); // perhaps OK for simple cases
IEnumerable<Query.Customer> Matching(Query.Customer.Specification specification); // for something more complex
}
}
我还创建了一个包含我的DTO的Query
命名空间。这意味着该域将包含Customer
AR,Query
名称空间也将包含Customer
,但是由于它位于Query
名称空间中,因此没有模棱两可,我不必添加DTO
后缀:
namespace Company.Project.DataAccess.Query
{
public class Customer
{
public class Specification
{
public string Name { get; private set; }
public Specification WithName(string name)
{
Name = name;
return this;
}
}
public string Name { get; set; }
public string Address { get; set; }
}
}
答案 1 :(得分:0)
dto是应用程序层的对象。您想要的是直接从数据库填充它。它是cqrs的查询方,在这里您没有像命令方那样的丰富域模型,而只有适合客户端的投影(dtos)。它们是查询(读取)模型。
更新:
这些是我使用的模式的对象,类似于命令,但是查询的结果是:
public interface QueryResult {}
纯DTO(或它们的列表),以及客户端的输出数据。
public interface Query<QR extends QueryResult> {}
在DTO中插入用于执行查询的输入数据(搜索条件)。
public interface QueryHandler <QR extends QueryResult, Q extends Query<QR>> {
public QR handle ( Q query );
}
执行查询的对象。
示例:
代码:
class EmployeeDto {
private String name;
private String email;
private String departmentName;
private double salary;
...
<<getters and setters>>
...
}
class EmployeeDtoList implements QueryResult {
private List<EmployeeDto> employeeDtos;
...
<<getter and setter>>
...
}
class EmployeesByAgeAndSalary implements Query<EmployeeDtoList> {
private Calendar maxAge;
private double minSalary;
...
<<getters and setters>>
...
}
class EmployeesByAgeAndSalaryHandler implements QueryHandler<EmployeeDtoList,EmployeesByAgeAndSalary> {
...
@Override
public EmployeeDtoList handle(EmployeesByAgeAndSalary query) {
...
<<retrieve from the database the data we need to return,
applying the criteria for the age and salary given in the "query" arg>>
...
}
}
- 客户端使用的外观是介体(此方法的接口):
public <QR extends QueryResult,Q extends Query<QR>> QR executeQuery(Q query);
介体将由管理查询处理程序注册表的类实现,以便将请求重定向到与给定查询关联的查询处理程序。
它类似于命令模式,但带有查询。
答案 2 :(得分:0)
这是一个很好的问题,
您将它们放在应用程序层中。您寻求的模式称为查询服务。
看看Vaughn Vernon(实现域驱动设计的作者)在他的github存储库中的表现如何:
然后,他直接从数据库中的查询服务(CQRS)中填充它们:
public ForumDiscussionsData forumDiscussionsDataOfId(String aTenantId, String aForumId) {
return this.queryObject(
ForumDiscussionsData.class,
"select "
+ "forum.closed, forum.creator_email_address, forum.creator_identity, "
+ "forum.creator_name, forum.description, forum.exclusive_owner, forum.forum_id, "
+ "forum.moderator_email_address, forum.moderator_identity, forum.moderator_name, "
+ "forum.subject, forum.tenant_id, "
+ "disc.author_email_address as o_discussions_author_email_address, "
+ "disc.author_identity as o_discussions_author_identity, "
+ "disc.author_name as o_discussions_author_name, "
+ "disc.closed as o_discussions_closed, "
+ "disc.discussion_id as o_discussions_discussion_id, "
+ "disc.exclusive_owner as o_discussions_exclusive_owner, "
+ "disc.forum_id as o_discussions_forum_id, "
+ "disc.subject as o_discussions_subject, "
+ "disc.tenant_id as o_discussions_tenant_id "
+ "from tbl_vw_forum as forum left outer join tbl_vw_discussion as disc "
+ " on forum.forum_id = disc.forum_id "
+ "where (forum.tenant_id = ? and forum.forum_id = ?)",
new JoinOn("forum_id", "o_discussions_forum_id"),
aTenantId,
aForumId);
}