1

我尝试使用 CQRS 以 DDD 方式实现一些应用程序。我使用 asp.net 核心应用程序,以及微软(在微服务书中)我使用 Mediatr。我想实现文章的过滤。为此,人们建议使用规范模式并将所有规范存储在域中(什么层应该包含 DDD 中的查询)。

但是如果我使用 dapper,我该如何处理解析表达式?使用 EF 不是问题,但使用原始 SQL 是。我认为将表达式树解析器和转换器实现为 SQL 是不值得的。更简单的方法是在 Domain 中存储一些 FilterModel,并通过在基础架构模型中遍历该模型来构建 SQL 或 SphinxQl。该解决方案是否符合 DDD 原则?我会很感激你的建议)

4

1 回答 1

1

典型的规范模式使用一种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);
        }
    }
}
于 2019-08-14T09:54:19.957 回答