使用存储库/服务层设计模式的建议
-
01-10-2019 - |
题
尝试在此处制作一个非常简单的存储库和服务层模式。 (.net 4,c#,linq,尽管这个问题是部分语言 - 敏捷的)。注意:这只是研发。
我的目标是最大程度地减少服务层中的方法定义的量。
这是我的存储库合同:
interface IFooRepository
{
IEnumerable<Foo> Find();
void Insert(Foo foo);
void Update(Foo foo);
void Delete(Foo foo);
}
那里没有新的。
现在,这是我(尝试)在我的服务合同中拥有的东西:
interface IFooDataService
{
public IEnumerable<Foo> Find(FooSearchArgs searchArgs);
}
从本质上讲,任何特定的“ foo”都有许多属性(ID,名称等),我希望能够搜索。
因此,我不想让每个不同属性的1倍查找方法,我只想要一个 - 这样,当我创建额外的属性时,我不必修改合同。
“ Foosearchargs”只是一个简单的POCO,具有所有不同的“ foo”属性。
所以,这就是我要做的,这是我的问题:
- 这是糟糕的设计吗?如果是这样,有什么选择?
- 如何在服务层中实现此过滤?我是否必须检查设置“ foosearchargs”的属性,然后继续过滤? (如果是这样,请查询。在哪里,如果这个地方查询,等等)任何人都有一个聪明的linq iEnumerable扩展方法来做到这一点吗? (IE
repository.WhereMeetsSearchCriteria(fooSearchArgs)
)
感谢帮助。
解决方案
我们使用非常相似的东西。您需要决定的一件事是,您是否要在存储库之外揭示可视性。您的查找方法返回iEnumerable,这可能是从您的子句中返回的可音机。
返回Iqueryable的优点是,您可以在存储库层之外进一步完善您的条件。
repository.Find(predicate).Where(x => x.SomeValue == 1);
只有在您使用返回的数据时,该表达式才会被编译,这是不利的。因为您只有在实际使用结果时才能点击数据库,您最终可能会在会话(NHIBERNATE)或连接已关闭后试图调用数据库。
我的个人偏爱是使用通过查找方法的规范模式使用iSpecification对象进行查询。
public interface ISpecification<TCandidate>
{
IQueryable<TCandidate> GetSatisfyingElements(IQueryable<TCandidate> source);
}
public class TestSpecification : ISpecification<TestEntity>
{
public IQueryable<TestEntity> GetSatisfyingElements(IQueryable<TestEntity> source)
{
return source.Where(x => x.SomeValue == 2);
}
}
public class ActiveRecordFooRepository: IFooRepository
{
...
public IEnumerable<TEntity> Find<TEntity>(ISpecification<TEntity> specification) where TEntity : class
{
...
return specification.GetSatisfyingElements(ActiveRecordLinq.AsQueryable<TEntity>()).ToArray();
...
}
public TEntity FindFirst<TEntity>(ISpecification<TEntity> specification) where TEntity : class
{
return specification.GetSatisfyingElements(ActiveRecordLinq.AsQueryable<TEntity>()).First();
}
}
查询运行后,从规范中返回的结果可汇总的存储库toarray或Tolist,以便在此处评估查询。尽管这似乎不如揭露可见性的灵活性,但它具有几个优势。
- 查询立即执行,并防止在会话结束后对数据库进行调用。
- 由于您的查询现在已捆绑到规格中,因此可以测试单位。
- 规格是可重复使用的,这意味着您在尝试运行类似的查询时没有代码重复,并且查询中的任何错误都只需要在一个地方固定。
- 使用正确的实施方式,您还可以将您的规格链接在一起。
repository.Find(
firstSpecification
.And(secondSpecification)
.Or(thirdSpecification)
.OrderBy(orderBySpecification));
其他提示
正在通过a 功能 作为服务层查找方法的参数,而不是foosearchargs,一个选项?枚举具有将func作为参数的Where方法(LINQ),因此您可以使用它来过滤结果。
不隶属于 StackOverflow