繁体   English   中英

是否可以创建Generic API GET操作?

[英]Is it possible to create a Generic API GET operation?

最近我创建了一个服务,它在我的API中有一些GET端点的逻辑(返回一些数据库表的所有值)。

为此创建服务的原因是我想在一个点上修改GET逻辑,而不是在将来必须在我的所有端点上更改它。

我创建了一个有效的测试服务,但因为我有超过50个表(DTO类),我想让服务更通用。

我现在已经实现了以下内容,这只是一个带有一个DTO类的GET操作的示例:

public interface IOMSService
{
    IEnumerable<CommodityViewModel> GetAll(); // Can I use <T> for this? - now I need to make interface properties for every OMS class (50+)
}

public class OMSService : IOMSService
{
    private MyDBContext _context;
    private IMapper _mapper;

    public OMSService(MyDBContext context, IMapper mapper)
    {
        _context = context;
        _mapper = mapper;
    }

    public IEnumerable<CommodityViewModel> GetAll() // How to make this more generic?
    {
        var result = this._context.Commodity
                     .Include(i => i.OmsCommodityMaterial);

        var CommodityVM = _mapper.Map<IList<CommodityViewModel>>(result);

        return CommodityVM;

    }
}

上面的例子GetAll ,但这意味着我需要为每个DTO类实现50多个接口属性和50个GetAll实现(因此不是改进而不是在端点本身中更改它)。

有没有办法让这更通用? 我认为接口和GetAll函数中IEnumerable的DTO部分应该是Generic类型(这样我才能在端点本身提供正确的ViewModel / DTO)。

我已经想到了这样的事情:

public interface IOMSService<T, U>
        where T : IEnumerable<U>
{
    T GetAll { get; }
}

有人能指出我正确的方向吗?

是的,使用泛型和DbContextSet<T>()方法,你可以这样做:

//Note we need to make the entity and the model it maps to generic
public IEnumerable<TModel> GetAll<TEntity, TModel>(
    params Expression<Func<TEntity, object>>[] includes)
    where TEntity : class
{
    var result = _context.Set<TEntity>().AsQueryable();

    if(includes != null)
    {
        foreach (var include in includes)
        {
            result = result.Include(include);
        }
    }

    return _mapper.Map<IList<TModel>>(result);
}

并称之为:

var allTheThings = GetAll<Commodity, CommodityViewModel>(i => i.OmsCommodityMaterial);

但是,要返回所有行几乎肯定是一个坏主意,所以为什么不在我们这里时添加一个过滤器:

public IEnumerable<TModel> Get<TEntity, TModel>(
    Expression<Func<TEntity, bool>> predicate, 
    params Expression<Func<TEntity, object>>[] includes) 
    where TEntity : class
{
    var result = _context.Set<TEntity>()
        .Where(predicate);

    if(includes != null)
    {
        foreach (var include in includes)
        {
            result = result.Include(include);
        }
    }

    return _mapper.Map<IList<TModel>>(result);
}

现在我们称之为:

var someOfTheThings = Get<Commodity, CommodityViewModel>(
    x => x.SomeProperty == 42,
    i => i.OmsCommodityMaterial);

如果你想从这个方法中提取一个接口,我可能会使接口通用:

public interface IOMSService<TEntity>
{
    IEnumerable<TModel> Get<TModel>(
        Expression<Func<TEntity, bool>> predicate, 
        params Expression<Func<TEntity, object>>[] includes) 
}

然后是一个基类:

public abstract class BaseOMSService<TEntity> : IOMSService<TEntity>
    where TEntity : class
{
    private MyDBContext _context;
    private IMapper _mapper;

    public BaseOMSService(MyDBContext context, IMapper mapper)
    {
        _context = context;
        _mapper = mapper;
    }

    public IEnumerable<TModel> Get<TModel>(
            Expression<Func<TEntity, bool>> predicate, 
            params Expression<Func<TEntity, object>>[] includes) 
    {
        var result = _context.Set<TEntity>()
            .Where(predicate);

        if(includes != null)
        {
            foreach (var include in includes)
            {
                result = result.Include(include);
            }
        }

        return _mapper.Map<IList<TModel>>(result);
    }
}

现在您可以创建特定的派生类:

public class CheeseOMSService : BaseOMSService<Cheese>
{
    // snip
}

public class ZombieOMSService : BaseOMSService<Zombie>
{
    // snip
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM