典型的规范模式使用一种bool IsSatisfiedBy(candidate)
结构。我发现这在创建数据存储查询时不太有用。我通常会使用直接从数据存储提供数据的IAggregateQuery
接口和实现(Aggregate
您感兴趣的相关聚合在哪里)。
如果您需要更复杂的东西(或者您只是更喜欢这样做),则IAggregateQuery
可以具有返回原语、 a DataRow
、 anIEnumerable<DataRow>
或在我的示例中降低 DTO读取模型的方法。
我通常将规范定义为读取模型中的嵌套类,以表示我可能需要的所有可能条件。
以下是我最近做的一个示例:
namespace MyDomain.DataAccess.Query
{
public class Customer // read model
{
public class Specification
{
public string NameMatch { get; private set; }
public Guid? Id { get; private set; }
public Specification MatchingName(string nameMatch)
{
NameMatch = nameMatch;
return this;
}
public Specification WithId(Guid id)
{
Id = id;
return this;
}
}
public Guid Id { get; set; }
public string Name { get; set; }
public string EMailAddress { get; set; }
}
}
namespace MyDomain.DataAccess
{
public class CustomerQuery : ICustomerQuery
{
private readonly IDatabaseGateway _databaseGateway;
private readonly IQueryMapper _queryMapper;
private readonly ICustomerQueryFactory _customerQueryFactory;
public CustomerQuery(IDatabaseGateway databaseGateway, IQueryMapper queryMapper, ICustomerQueryFactory customerQueryFactory)
{
Guard.AgainstNull(databaseGateway, nameof(databaseGateway));
Guard.AgainstNull(queryMapper, nameof(queryMapper));
Guard.AgainstNull(customerQueryFactory, nameof(customerQueryFactory));
_databaseGateway = databaseGateway;
_queryMapper = queryMapper;
_customerQueryFactory = customerQueryFactory;
}
public IEnumerable<Query.Customer> Matching(Query.Customer.Specification specification)
{
return _queryMapper.MapObjects<Query.Customer>(_customerQueryFactory.Matching(specification));
}
public int CountMatching(Query.Customer.Specification specification)
{
return _databaseGateway.GetScalarUsing<int>(_customerQueryFactory.CountMatching(specification));
}
}
}
namespace MyDomain.DataAccess
{
public class CustomerQueryFactory : ICustomerQueryFactory
{
private const string SelectFrom = @"
select
Id,
Name,
EMailAddress
from
Customer
";
public IQuery Matching(Query.Customer.Specification specification)
{
return Matching(specification, false);
}
public IQuery CountMatching(Query.Customer.Specification specification)
{
return Matching(specification, true);
}
private static IQuery Matching(Query.Customer.Specification specification, bool count)
{
return RawQuery.Create(string.Concat(count ? "select count(*) from Customer" : SelectFrom, @"
where
(
@Id is null
or
Id = @Id
)
and
(
isnull(@Name, '') = ''
or
Name like '%' + @Name + '%'
)
", count ? string.Empty : "order by Name"))
.AddParameterValue(Columns.Id, specification.Id)
.AddParameterValue(Columns.Name, specification.NameMatch);
}
}
}