3

我知道标题不好。

我有一个包含我所有实体功能的服务。

在我的服务中,有一个具有这种结构的功能

IList<T> GetAllPaged<TKey>(
    List<Expression<Func<T, bool>>> predicate, 
    Expression<Func<T, TKey>> orderKeySelector
);

此函数从一个实体获取数据并对其进行排序。

现在我想做更多。

首先从一个实体中选择,然后按顺序对其进行分组,最后从分组项目中选择新项目。

像这样的东西:

IList<TReturn> GetAllPaged<TResult, TKey, TGroup, TReturn>(
    List<Expression<Func<T, bool>>> predicate, 
    Expression<Func<T, TResult>> firstSelector, 
    Expression<Func<TResult, TKey>> orderSelector, 
    Func<TResult, TGroup> groupSelector, 
    Func<IGrouping<TGroup, TResult>, TReturn> selector
);

那可能吗?

4

2 回答 2

2

这是我认为您要求的解决方案。

首先,基础存储库。我创建了一个基础存储库,因为我希望您不会将这种疯狂暴露给应用程序,而只会暴露给存储库。

abstract class BaseRepo<TEntity>
{
    // If you're using Entity Framework, this method could 
    // be implemented here instead.
    protected abstract IQueryable<TEntity> Entities { get; }

    protected IList<TReturn> GetAllPaged<TResult, TKey, TGroup, TReturn>(
        List<Expression<Func<TEntity, bool>>> predicates,
        Expression<Func<TEntity, TResult>> firstSelector,
        Expression<Func<TResult, TKey>> orderSelector,
        Func<TResult, TGroup> groupSelector,
        Func<IGrouping<TGroup, TResult>, TReturn> selector)
    {
        return predicates
            .Aggregate(Entities, (current, predicate) => current.Where(predicate))
            .Select(firstSelector)
            .OrderBy(orderSelector)
            .GroupBy(groupSelector)
            .Select(selector)
            .ToList();
    }
}

然后执行。

class HorseRepo : BaseRepo<Horse>
{
    // This will of course be some data source
    protected override IQueryable<Horse> Entities
    {
        get
        {
            return new List<Horse> {
                new Horse { Id = 1, Name = "Mr Horse", Color = "Brown" },
                new Horse { Id = 2, Name = "Mrs Horse", Color = "White" },
                new Horse { Id = 3, Name = "Jr Horse", Color = "White" },
                new Horse { Id = 4, Name = "Sr Horse", Color = "Black" },
                new Horse { Id = 5, Name = "Dr Horse", Color = "Brown" },
            }.AsQueryable();
        }
    }

    // This is what I think you should expose to the application
    // This is the usage of the expression fest above.
    public IEnumerable<GroupedHorses> GetGroupedByColor() {
        return horseRepo.GetAllPaged(
            new List<Expression<Func<Horse, bool>>> {
                h => h.Name != string.Empty, 
                h => h.Id > 0
            },
            h => new HorseShape { Id = h.Id, Name = h.Name, Color = h.Color },
            hs => hs.Name,
            hs => hs.Color,
            g => new GroupedHorses
            {
                Color = g.Key,
                Horses = g.ToList()
            }
        );
    }
}

需要一些类:

class GroupedHorses
{
    public string Color { get; set; }
    public IList<HorseShape> Horses { get; set; }
}

class HorseShape
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Color { get; set; }
}

// Define other methods and classes here
class Horse
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Color { get; set; }
    public string UninterestingProperty { get; set; }
}
于 2013-11-12T10:34:22.533 回答
1

也许你可以传递一个对你的实体做某事的通用函数?我知道表达式很有趣,但你应该始终考虑最终结果是否比更简单的结果更好。

像这样的东西:

TResult Query<TEntity, TResult>(Func<IQueryable<TEntity>, TResult> queryFunction)

实体框架的实现:

using(var context = new SomeContext())
{
    return queryFunction(context.Set<TEntity>());
}

用法:

var listOfCars = carService.Query(cars => cars
    .Select(c => new { Id = c.Id, Name = c.Name })  // c stands for car
    .GroupBy(a => a.Name) // a stands for "anonymous object"
    .OrderBy( /* order your group in some fashion */)
    .ToList()
);

如果你把所有这些逻辑放在单独的参数中,你将失去使用匿名对象的能力,你会发现自己编写了很多服务方法。

于 2013-11-12T09:10:21.260 回答