尝试在此处创建一个非常简单的存储库和服务层模式。 (.NET 4,C#,LINQ,虽然这个问题部分与语言无关)。注意:这只是R& D。
我的目标是尽量减少服务层中方法定义的数量。
这是我的存储库合同:
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,name等),我希望能够搜索到它们。
所以,我不想为每个不同的属性使用1x Find方法,我只想要一个 - 当我创建额外的属性时,我不必修改合同。
“FooSearchArgs”只是一个简单的POCO,具有所有不同的“Foo”属性。
所以,这就是我想要做的,这是我的问题:
repository.WhereMeetsSearchCriteria(fooSearchArgs)
)感谢帮助。
答案 0 :(得分:3)
我们使用非常相似的东西。您需要决定的一件事是,您是否要在存储库之外公开IQueryable。你的find方法返回IEnumerable,它可能是你的when子句返回的IQueryable。
返回IQueryable的优点是您可以在存储库层之外进一步优化您的条件。
repository.Find(predicate).Where(x => x.SomeValue == 1);
只有在使用返回的数据时才会编译表达式,这里的缺点就在于此。因为您只是在实际使用结果时才点击数据库,所以在您的会话(nhibernate)或连接关闭后,您最终可能会尝试调用数据库。
我个人的偏好是使用您传递find方法的规范模式,并使用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();
}
}
在运行查询之后,存储库会对从规范返回的结果IQueryable调用ToArray或ToList,以便在那里评估查询。虽然这似乎不如暴露IQueryable灵活性,但它具有几个优点。
repository.Find(
firstSpecification
.And(secondSpecification)
.Or(thirdSpecification)
.OrderBy(orderBySpecification));
答案 1 :(得分:0)
将Func作为参数传递给服务层的Find方法,而不是FooSearchArgs,这是一个选项吗? Enumerables有一个Where方法(linq),它将Func作为参数,因此您可以使用它来过滤结果。