保理IQueryable中的WHERE子句

时间:2016-10-03 09:38:10

标签: c# linq refactoring

我恢复了一些意大利面条代码,我必须重构它。我不想要一个超过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);
}

2 个答案:

答案 0 :(得分:1)

这个似乎对我来说太过分了(但我想这是评论中出现的多态性),但无论如何,它是:

我们从界面开始:

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

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

答案 1 :(得分:0)

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

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