有没有办法在Ardalis中结合规范类。规范库?

发布于 2025-02-09 10:31:29 字数 965 浏览 2 评论 0原文

我是Ardalis的新手。规范库和一般干净的体系结构。我想知道是否有一种方法可以分组多个规范类以进行可合算的查询。对于涉及大量变量的复杂查询将有助于分类并避免过度使用条件语句。

例如,我可能需要按优点或劣等分类DateTime属性,而不是添加多个条款,具体取决于客户端请求的配置,并根据请求的性质包括不同的相关实体(它们本身, ,可能会根据标准查询)。

以下示例并不能很好地说明我需要做的事情,但这可能会有所帮助。

1/根据其个人资料的完成状态获取联系列表。

public ContactByCompletion(bool IsComplete)
{
    Query
        .Where(prop => prop.IsComplete == IsComplete)
        .OrderByDescending(ord => ord.CreatedAt);
}

2/与参数

public ContactByCreationDateSuperiorThan(DateTime dateRef)
{
    Query
        .Where(prop => prop.CreatedAt > dateRef.Date);
}

3/获取隶属于给定国家的联系人列表的联系人列表的列表

public ContactByCountry(string countryCode)
{
    Guard.Against.NullOrEmpty(countryCode, nameof(countryCode));

    Query
        .Where(prop => prop.CountryCode == countryCode);
}

,因此在这个非常简单的示例中,这个想法是将这些查询组合起来,以形成一个使您接触的查询拥有一个完整的状态,该状态居住在一个给定的国家,是在有关日期之后创建的。有没有办法实现这一目标?

I am new to the Ardalis.Specification library and to the Clean Architecture in general. I was wondering if there might be a way to group multiple specification classes to make a composable query. It would be helpful for complex queries involving a large set of variables to sortBy and avoid excessive use of conditional statements.

I may need for example to sort a DateTime property either by Superior than or Inferior than, to add multiple Where clauses depending on the configuration of the request by the client and to include different related entities depending on the nature of the request (which, themselves, might be queried based on a criteria).

The following example is not a good illustration of what i need to do but that might help.

1/ Gets a list of Contact based on the state of Completion of their profile.

public ContactByCompletion(bool IsComplete)
{
    Query
        .Where(prop => prop.IsComplete == IsComplete)
        .OrderByDescending(ord => ord.CreatedAt);
}

2/ Gets a list of Contacts with a creation Date later than the parameter

public ContactByCreationDateSuperiorThan(DateTime dateRef)
{
    Query
        .Where(prop => prop.CreatedAt > dateRef.Date);
}

3/ Gets a list of Contacts affiliated to a given country

public ContactByCountry(string countryCode)
{
    Guard.Against.NullOrEmpty(countryCode, nameof(countryCode));

    Query
        .Where(prop => prop.CountryCode == countryCode);
}

So in this very simplistic example, the idea would be to combine these queries to form one that gets you the Contacts with a completed state that reside on a given country and that were created after the date in question. Is there a way to achieve that?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

卸妝后依然美 2025-02-16 10:31:29

我需要这个,所以我提出了一个解决方案。希望其他人也能利用这一点。

public class MergedSpecification<T> : Specification<T>, ISpecification<T>
{
    private readonly ISpecification<T>[] _specs;

    /// <summary>
    /// Initializes a new instance of the <see cref="MergedSpecification{T}"/> class.
    /// </summary>
    /// <param name="spec">The spec.</param>
    /// <param name="specs">The specs.</param>
    public MergedSpecification(params ISpecification<T>[] specs)
    {
        _specs = specs;
    }

    public TSpec? GetSpec<TSpec>() where TSpec : ISpecification<T>
    {
        return _specs.OfType<TSpec>().FirstOrDefault();
    }

    public override IEnumerable<T> Evaluate(IEnumerable<T> entities)
    {
        entities = entities.ToArray();
        foreach (var spec in _specs)
        {
            entities = Evaluator.Evaluate(entities, spec);
        }

        return entities;
    }

    IEnumerable<WhereExpressionInfo<T>> ISpecification<T>.WhereExpressions => _specs.SelectMany(spec => spec.WhereExpressions);
    IEnumerable<OrderExpressionInfo<T>> ISpecification<T>.OrderExpressions => _specs.SelectMany(spec => spec.OrderExpressions);
    IEnumerable<IncludeExpressionInfo> ISpecification<T>.IncludeExpressions => _specs.SelectMany(spec => spec.IncludeExpressions);
    IEnumerable<string> ISpecification<T>.IncludeStrings => _specs.SelectMany(spec => spec.IncludeStrings);
    IEnumerable<SearchExpressionInfo<T>> ISpecification<T>.SearchCriterias => _specs.SelectMany(spec => spec.SearchCriterias);

    int? ISpecification<T>.Take => _specs.FirstOrDefault(s => s.Take != null)?.Take;
    int? ISpecification<T>.Skip => _specs.FirstOrDefault(s => s.Skip != null)?.Skip;

    Func<IEnumerable<T>, IEnumerable<T>>? ISpecification<T>.PostProcessingAction => results =>
    {
        foreach (var func in _specs.Select(s => s.PostProcessingAction))
        {
            if (func != null)
            {
                results = func(results);
            }
        }

        return results;
    };

    string? ISpecification<T>.CacheKey => $"MergedSpecification:{string.Join(':', _specs.Select(s => s.CacheKey))}";
    bool ISpecification<T>.CacheEnabled => _specs.Any(s => s.CacheEnabled);
    bool ISpecification<T>.AsNoTracking => _specs.Any(s => s.AsNoTracking);
    bool ISpecification<T>.AsSplitQuery => _specs.Any(s => s.AsSplitQuery);
    bool ISpecification<T>.AsNoTrackingWithIdentityResolution => _specs.Any(s => s.AsNoTrackingWithIdentityResolution);
    bool ISpecification<T>.IgnoreQueryFilters => _specs.Any(s => s.IgnoreQueryFilters);
}

I needed this so I came up with a solution. Hope others also get use out of this.

public class MergedSpecification<T> : Specification<T>, ISpecification<T>
{
    private readonly ISpecification<T>[] _specs;

    /// <summary>
    /// Initializes a new instance of the <see cref="MergedSpecification{T}"/> class.
    /// </summary>
    /// <param name="spec">The spec.</param>
    /// <param name="specs">The specs.</param>
    public MergedSpecification(params ISpecification<T>[] specs)
    {
        _specs = specs;
    }

    public TSpec? GetSpec<TSpec>() where TSpec : ISpecification<T>
    {
        return _specs.OfType<TSpec>().FirstOrDefault();
    }

    public override IEnumerable<T> Evaluate(IEnumerable<T> entities)
    {
        entities = entities.ToArray();
        foreach (var spec in _specs)
        {
            entities = Evaluator.Evaluate(entities, spec);
        }

        return entities;
    }

    IEnumerable<WhereExpressionInfo<T>> ISpecification<T>.WhereExpressions => _specs.SelectMany(spec => spec.WhereExpressions);
    IEnumerable<OrderExpressionInfo<T>> ISpecification<T>.OrderExpressions => _specs.SelectMany(spec => spec.OrderExpressions);
    IEnumerable<IncludeExpressionInfo> ISpecification<T>.IncludeExpressions => _specs.SelectMany(spec => spec.IncludeExpressions);
    IEnumerable<string> ISpecification<T>.IncludeStrings => _specs.SelectMany(spec => spec.IncludeStrings);
    IEnumerable<SearchExpressionInfo<T>> ISpecification<T>.SearchCriterias => _specs.SelectMany(spec => spec.SearchCriterias);

    int? ISpecification<T>.Take => _specs.FirstOrDefault(s => s.Take != null)?.Take;
    int? ISpecification<T>.Skip => _specs.FirstOrDefault(s => s.Skip != null)?.Skip;

    Func<IEnumerable<T>, IEnumerable<T>>? ISpecification<T>.PostProcessingAction => results =>
    {
        foreach (var func in _specs.Select(s => s.PostProcessingAction))
        {
            if (func != null)
            {
                results = func(results);
            }
        }

        return results;
    };

    string? ISpecification<T>.CacheKey => 
quot;MergedSpecification:{string.Join(':', _specs.Select(s => s.CacheKey))}";
    bool ISpecification<T>.CacheEnabled => _specs.Any(s => s.CacheEnabled);
    bool ISpecification<T>.AsNoTracking => _specs.Any(s => s.AsNoTracking);
    bool ISpecification<T>.AsSplitQuery => _specs.Any(s => s.AsSplitQuery);
    bool ISpecification<T>.AsNoTrackingWithIdentityResolution => _specs.Any(s => s.AsNoTrackingWithIdentityResolution);
    bool ISpecification<T>.IgnoreQueryFilters => _specs.Any(s => s.IgnoreQueryFilters);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文