在IQueryable中分解WHERE子句

本文关键字:WHERE 子句 分解 IQueryable | 更新日期: 2023-09-27 18:09:55

我恢复了一些意大利面条代码,我必须重构它。我不想要一个超过200行的方法,对我来说它不是面向对象的编程。我正在考虑这个问题,想听听你的建议。

这是我的代码:

第18行

if (searchCriteria.EventReference != null)
{
    query = query.Search(x = > x.EventReference, searchCriteria.EventReference);
}
if (searchCriteria.PendingEvent == false)
{
    query = query.Where(x = > x.EventStatusId != EventStatus.Pending);
}
if (searchCriteria.VerifiedEvent == false)
{
    query = query.Where(x = > x.EventStatusId != EventStatus.Verified);
}
if (searchCriteria.CanceledEvent == false)
{
    query = query.Where(x = > x.EventStatusId != EventStatus.Canceled);
}

第237行

if (searchCriteria.RemitterId != null)
{
    query = query.Where(x = > x.Trade.RemitterId == searchCriteria.RemitterId);
}

在IQueryable中分解WHERE子句

这个对我来说似乎是多余的(但我猜这是评论中出现的多态性),但无论如何,它就是:

我们从接口开始:

public interface IQueryFilter
{
    IQueryable<Whatever> Filter(IQueryable<Whatever> query, SearchCriteria searchCriteria);
}

然后实现公共属性:

public abstract class AQueryFilter<T> : IQueryFilter
{
    public AQueryFilter(Func<SearchCriteria, T> criteria)
    {
        Criteria = criteria;
    }
    protected Func<SearchCriteria, T> Criteria { get; }
    public abstract IQueryable<Whatever> Filter(IQueryable<Whatever> query, SearchCriteria searchCriteria);
}

最后,所有具体的东西:

public class WhereEventStatusQueryFilter : AQueryFilter<bool>
{
    private EventStatus _toTest;
    public WhereEventStatusQueryFilter(Func<SearchCriteria, bool> criteria, EventStatus toTest)
        : base(criteria)
    {
        _toTest = toTest;
    }
    public override IQueryable<Whatever> Filter(IQueryable<Whatever> query, SearchCriteria searchCriteria)
    {
        return (Criteria(searchCriteria) ? query : query.Where(x => x.EventStatusId != _toTest));
    }
}
public class SearchQueryFilter : AQueryFilter<object>
{
    Func<Whatever, object> _searchFor;
    public SearchQueryFilter(Func<SearchCriteria, object> criteria, Func<Whatever, object> searchFor)
        : base(criteria)
    {
        _searchFor = searchFor;
    }
    public override IQueryable<Whatever> Filter(IQueryable<Whatever> query, SearchCriteria searchCriteria)
    {
        return (Criteria(searchCriteria) == null ? query : query.Search(x => _searchFor(x), Criteria(searchCriteria)));
    }
}
public class WhereEqualQueryFilter : AQueryFilter<object>
{
    Func<Whatever, object> _searchFor;
    public WhereEqualQueryFilter(Func<SearchCriteria, object> criteria, Func<Whatever, object> searchFor)
        : base(criteria)
    {
        _searchFor = searchFor;
    }
    public override IQueryable<Whatever> Filter(IQueryable<Whatever> query, SearchCriteria searchCriteria)
    {
        return (Criteria(searchCriteria) == null ? query : query.Where(x => _searchFor(x) == Criteria(searchCriteria)));
    }
}

用法:

var filters = new IQueryFilter[]
{
    new WhereEventStatusQueryFilter(x => x.PendingEvent, EventStatus.Pending),
    new WhereEventStatusQueryFilter(x => x.VerifiedEvent, EventStatus.Verified),
    new SearchQueryFilter(x => x.EventReference, x => x.EventReference),
    new WhereEqualQueryFilter(x => x.RemittedId, x => x.Trade.RemittedId),
    ...
};
foreach (var filter in filters)
    query = filter.Filter(query, searchCriteria);

但是这个解决方案隐藏了很多逻辑。如果有人想添加一些东西,他必须阅读所有以前的过滤器类,以了解是否已经有一个可以完成工作,或者他是否必须编写另一个。

嗯,我不认为这真的更好,但你可以这样做:

var searchDict = new Dictionary<Func<bool>, Func<IQueryable<?>>>()
{
    { () => searchCriteria.EventReference != null, query.Search(x = > x.EventReference, searchCriteria.EventReference) },
    { () => searchCriteria.VerifiedEvent == false, query.Where(x = > x.EventStatusId != EventStatus.Verified) },
    { () => searchCriteria.RemitterId != null, query.Where(x = > x.Trade.RemitterId == searchCriteria.RemitterId) },
    ...
};
foreach (var item in seachDict)
    if (item.First())
        query = item.Second();

或者(取决于你想在哪里以及如何创建你的字典):

var searchDict = new Dictionary<Func<SearchCriteria, bool>, Func<IQueryable<?>, IQueryable<?>>>()
{
    { c => c.EventReference != null, q => q.Search(x = > x.EventReference, searchCriteria.EventReference)},
    { c => c.VerifiedEvent == false, q => q.Where(x = > x.EventStatusId != EventStatus.Verified) },
    { c => c.RemitterId != null, q => q.Where(x = > x.Trade.RemitterId == searchCriteria.RemitterId) },
    ...
};
foreach (var item in seachDict)
    if (item.First(searchCriteria))
        query = item.Second(query);