是否有一种方法可以在Ardalis中组合Specification类?规范图书馆吗?



我是新来的。规范库和清洁体系结构。我想知道是否有一种方法可以将多个规范类分组以生成可组合的查询。这将有助于涉及大量变量的复杂查询,并避免过度使用条件语句。

例如,我可能需要按Superior than或Inferior than对DateTime属性进行排序,根据客户端请求的配置添加多个Where子句,并根据请求的性质包括不同的相关实体(它们本身可能基于标准进行查询)。

下面的例子不能很好地说明我需要做什么,但这可能会有所帮助。

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);
}

因此,在这个非常简单的示例中,我们的想法是将这些查询组合成一个查询,为您提供位于给定国家的完整状态的联系人,并且在所讨论的日期之后创建。有办法做到这一点吗?

我需要这个,所以我想出了一个解决方案。希望其他人也能从中受益。

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);
}

最新更新