简体   繁体   English

CQRS 架构模式中的查询处理程序

[英]Query handlers in CQRS architectural pattern

I'm starting with CQRS and I think I'm not quite sure how (or if it's Ok to do it) to add a query that can have filtering and ordering on the result of the final query.我从 CQRS 开始,我想我不太确定如何(或者是否可以这样做)添加一个可以对最终查询的结果进行过滤和排序的查询。 For example:例如:

public partial class GetParticipantListQuery : IRequest<IList<ParticipantDto>>
{
    public Expression<Func<ParticipantDto, bool>> Filter { get; set; } = null;
    public Func<IQueryable<ParticipantDto>, IQueryable<ParticipantDto>> OrderBy { get; set; } = null;
}

Then in the handler apply the filtering and ordering to the corresponding result from the DB Is this a good option?然后在处理程序中将过滤和排序应用于数据库中的相应结果这是一个不错的选择吗? How can I achieve this kind of thing in my queries?我怎样才能在我的查询中实现这种事情? My goal is to avoid creating one query for each filter I need, like "GetParticipantsByNameQuery", "GetParticipantsByTeamIdQuery" and so on an so forth我的目标是避免为我需要的每个过滤器创建一个查询,例如“GetParticipantsByNameQuery”、“GetParticipantsByTeamIdQuery”等等

You can pass in a filter class which contains the necessary properties to filter the result.您可以传入一个过滤器 class ,其中包含过滤结果所需的属性。

For example:例如:

public class Filter
{
    //Property Name
    public string Key { get; set; }
    //Property Type eg. string, int, bool
    public string Type { get; set; }
    //Value to filter
    public object Value { get; set; }
}

var result = from u in _context.Set<T>() select u;
switch(filter.Type)
{
    case "string":
        result = result.Where(e => EF.Property<string>(e, filter.Key).Equals((string)filter.Value));
}

This is just an example for string type, you can add your own type in the switch block to filter other types.这只是字符串类型的示例,您可以在 switch 块中添加自己的类型以过滤其他类型。

The way I approach my query side is as follows:-我接近我的查询方面的方式如下: -

I have a namespace that represents my query objects in order not to conflict with my domain.我有一个代表我的查询对象的命名空间,以免与我的域发生冲突。

The domain may be something like this:域可能是这样的:

namespace Product
{
    public class Order
    {
        public Guid Id { get; }
        public DateTime RegisteredDate { get; }

        public Order(Guid id, DateTime registeredDate)
        {
            Id = id;
            RegisteredDate = registeredDate;
        }
    }
}

The read model will look something like this (note the nested Specification class):读取的 model看起来像这样(注意嵌套的Specification类):

namespace Product.DataAccess.Query
{
    public class Order
    {
        public class Specification
        {
            public Guid? Id { get; private set; }
            public DateTime? RegisteredDateStart { get; private set; }
            public DateTime? RegisteredDateEnd { get; private set; }

            public Specification WithId(Guid id)
            {
                Id = id;

                return this;
            }

            public Specification WithRegisteredDateStart(DateTime registeredDateStart)
            {
                RegisteredDateStart = registeredDateStart;

                return this;
            }

            public Specification WithRegisteredDateEnd(DateTime registeredDateEnd)
            {
                RegisteredDateEnd = registeredDateEnd;

                return this;
            }
        }

        public Guid Id { get; set; }
        public DateTime RegisteredDate { get; set; }
    }
}

In my query layer I pass the specification over and the query layer can then construct the query using the specification values:在我的查询层中,我传递了规范,然后查询层可以使用规范值构造查询:

namespace Product.DataAccess
{
    public interface IOrderQuery
    {
        IEnumerable<Query.Order> Search(Query.Order.Specification specification);
        int Count(Query.Order.Specification specification);
    }
}

In this way you have an explicit requirement passed to your query layer and you refactor your specification class and the query implementation when you need further querying options.通过这种方式,您可以将明确的要求传递给查询层,并在需要进一步查询选项时重构规范 class 和查询实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM