public interface ILocationRepository
{
IList<Location> FindAll(int start, int size);
IList<Location> FindForState(State state, int start, int size);
IList<Location> FindForPostCode(string postCode, int start, int size);
}
public class MyRepository
{
IQueryable<Location> FindAll()
{
List<Location> myLocations = ....;
return myLocations.AsQueryable<Location>;
// here Query can only be applied on this
// subset, not directly to the database
}
}
第一个方法比内存有优势,因为您将返回更少的数据而不是全部。
As mentioned by previous answer, exposing IQueryable gives access to callers to play with IQueryable itself, which is or it can become dangerous.
Encapsulating business logic's first responsibility is to maintain integrity of your database.
You can continue exposing IList and may be change your parameters as following, this is how we are doing...
public interface ILocationRepository
{
IList<Location> FindAll(int start, int size);
IList<Location> FindForState(State state, int start, int size);
IList<Location> FindForPostCode(string postCode, int start, int size);
}
if size == -1 then return all...
Alternative way...
If you still want to return IQueryable, then you can return IQueryable of List inside your functions.. for example...
public class MyRepository
{
IQueryable<Location> FindAll()
{
List<Location> myLocations = ....;
return myLocations.AsQueryable<Location>;
// here Query can only be applied on this
// subset, not directly to the database
}
}
First method has an advantage over memory, because you will return less data instead of all.
Your repository is no longer properly unit testable; you can't rely on a: it working, b: what it does;
the caller could add a non-translatable function (i.e. no TSQL mapping; breaks at runtime)
the caller could add a filter/sort that makes it perform like a dog
Since callers expect IQueryable<T> to be composable, it rules out non-composable implementations - or it forces you to write your own query provider for them
it means you can't optimize / profile the DAL
For stability, I've taken to not exposing IQueryable<T> or Expression<...> on my repositories. This means I know how the repository behaves, and my upper layers can use mocks without worrying "does the actual repository support this?" (forcing integration tests).
I still use IQueryable<T> etc inside the repository - but not over the boundary. I posted some more thoughts on this theme here. It is just as easy to put paging parameters on the repository interface. You can even use extension methods (on the interface) to add optional paging parameters, so that the concrete classes only have 1 method to implement, but there may be 2 or 3 overloads available to the caller.
发布评论
评论(3)
正如前面的答案所提到的,公开 IQueryable 可以让调用者访问 IQueryable 本身,这是危险的,或者可能会变得危险。
封装业务逻辑的首要责任是维护数据库的完整性。
您可以继续公开 IList,并可以按如下方式更改您的参数,这就是我们正在做的...
如果 size == -1 则返回所有...
替代方式...
如果您仍然这样做想要返回 IQueryable,那么您可以在函数内返回 IQueryable 的 List。例如...
第一个方法比内存有优势,因为您将返回更少的数据而不是全部。
As mentioned by previous answer, exposing IQueryable gives access to callers to play with IQueryable itself, which is or it can become dangerous.
Encapsulating business logic's first responsibility is to maintain integrity of your database.
You can continue exposing IList and may be change your parameters as following, this is how we are doing...
if size == -1 then return all...
Alternative way...
If you still want to return IQueryable, then you can return IQueryable of List inside your functions.. for example...
First method has an advantage over memory, because you will return less data instead of all.
我建议使用
IEnumerable
而不是IList
,使用它您将拥有更大的灵活性。这样,您将能够从 Db 中仅获取您真正要使用的那部分数据,而无需在存储库中完成额外的工作。
示例:
超级干净简单。
I recommend using
IEnumerable
instead ofIList
, with it you will have more flexibility.This way you will be able to get from Db only that portion of data which you really gonna use without extra work done in your repository.
Sample:
Which is super clean and simple.
优点; 可组合性:
缺点; 不可测试性:
IQueryable
IQueryable为了稳定性,我采取了不< /strong> 在我的存储库上公开
IQueryable
或Expression<...>
。 这意味着我知道存储库的行为方式,并且我的上层可以使用模拟,而不必担心“实际存储库支持这个吗?” (强制集成测试)。我仍然在存储库内部使用
IQueryable
等 - 但不会超出边界。 我在此发布了一些关于此主题的更多想法。 在存储库界面上放置分页参数也同样容易。 您甚至可以使用扩展方法(在接口上)添加可选分页参数,以便具体类只有 1 个方法要实现,但可能有 2 或 3 个重载可供调用者使用。The pros; composability:
The cons; non-testability:
IQueryable<T>
to be composable, it rules out non-composable implementations - or it forces you to write your own query provider for themFor stability, I've taken to not exposing
IQueryable<T>
orExpression<...>
on my repositories. This means I know how the repository behaves, and my upper layers can use mocks without worrying "does the actual repository support this?" (forcing integration tests).I still use
IQueryable<T>
etc inside the repository - but not over the boundary. I posted some more thoughts on this theme here. It is just as easy to put paging parameters on the repository interface. You can even use extension methods (on the interface) to add optional paging parameters, so that the concrete classes only have 1 method to implement, but there may be 2 or 3 overloads available to the caller.