我创建了一个必须从数据库中获取元素的服务。在开发生命周期中,该服务不断发展,现在我有很多方法可以按ID,类别,名称等获取元素。
现在,我试图不返回IEnumerable,而是Iqueryable,并在方法中构建Where子句,即调用服务,但我认为这不是正确的方法。当然,如果在哪里重复了Where子句,我将尝试在服务中移动重复的代码,并使用之前创建的Iqueryable。
OLD:
import Measure from '../src/testing'
describe('Measure Class', () => {
const measure = new Measure(1, 'm')
// Number() - works!
test('Number', () => {
const number = Number(measure)
expect(number).toBe(1)
})
// String - works!
test('String', () => {
const string = String(measure)
expect(string).toBe('1m')
})
/**
* Number context - fails!
* Operator '+' cannot be applied to types '1' and 'Measure'.ts(2365)
*/
test('Number + Measure', () => {
const number = 1 + measure
expect(number).toBe(2)
})
/**
* String context - fails!
* Expected: "is: 1m"
* Received: "is: 1"
*/
test('String + Measure', () => {
const string = 'is: ' + measure
expect(string).toBe('is: 1m')
})
})
现在:
public async Task<IEnumerable<Element>> GetElementsByIds(List<int> elementsIds)
{
var elements = await _context.Elements
.Include(e => e.ElementCategories)
.Include(e=>e.ElementSth)
.Where(e => elementsIds.Contains(e.Id))
.ToListAsync();
if (!elements.Any())
{
throw new NotFoundException(nameof(Element), elementsIds);
}
return elements;
}
public async Task<IEnumerable<Element>> GetElementsPerCategory(string categoryName)
{
var elements = await _context.Elements
.Include(e => e.ElementCategories)
.Include(e=>e.ElementSth)
.Where(c=>c.Category.Name == categoryName)
.ToListAsync();
if (!elements.Any())
{
throw new NotFoundException(nameof(Element), elementsIds);
}
return elements;
}
我想重构服务并以更好的方式创建将来的服务。您对这个问题有经验吗?
答案 0 :(得分:1)
直接公开IQueryable<>
是非常不同的事情,因为它基本上允许对数据库执行任何操作。根据实际查询的内容,甚至您的.Include()
调用也可能会被忽略。
在内部服务中公开可查询的内容是编写非常有效的查询的好方法(因为这样便可以得到他们实际需要的内容)。对于不太内部使用或面向公众的API,我真的建议不要直接公开可查询对象以保留控件。
话虽如此,如果您只是想避免代码重复,可以引入一个辅助方法来执行实际的查询,并在方法中传递不同的过滤器:
public async Task<IEnumerable<Element>> GetElementsByIds(List<int> elementsIds)
{
return await GetElementsInternal(_context.Elements.Where(e => elementsIds.Contains(e.Id)));
}
public async Task<IEnumerable<Element>> GetElementsPerCategory(string categoryName)
{
return await GetElementsInternal(_context.Elements.Where(e => e.Category.Name == categoryName));
}
private async Task<IEnumerable<Element>> GetElementsInternal(IQueryable<Element> queryable)
{
var elements = queryable
.Include(e => e.ElementCategories)
.Include(e => e.ElementSth)
.ToListAsync();
if (!elements.Any())
{
throw new NotFoundException(nameof(Element), elementsIds);
}
return elements;
}