我如何重构这个 IQueryable存储库方法?
我正在开发 .NET 4 应用程序、C#、Entity Framework 4、SQL Server 2008。
我的数据库中有 7 个表,每个表代表一个特定级别的位置(国家、州、城市、社区等)。
现在,在我的存储库中,我尝试定义一个只有一个 Find() 方法的接口协定。为此,我创建了一个名为“Location”的抽象类,POCO 位置均继承自该抽象类。
这是我目前拥有的方法:
public IQueryable<Location> Find()
{
return AllCountries()
.Union(AllStates())
.Union(AllCounties())
.Union(AllCities())
.Union(AllNeigbourhoods())
.Union(AllZipCodes())
.Union(AllStreets());
}
那些内联方法(例如 AllStates)是私有的 IQueryable 方法,例如:
private IQueryable<Location> AllCountries()
{
var db = new MyCustomDataContext();
return db.Countries;
}
这一切都工作正常,但我不喜欢 Find() 方法中代码的外观。
本质上,我想要一个返回所有国家/城市/州等的存储库方法(作为 IQuerable
)。
这样,我的服务层可以执行以下操作:
var countries = repository.Find(somePredicate).OfType<Country>().ToList();
或者这样:
var countries = repository.Find(somePredicate).OfType<City>().ToList();
所以我只需要声明一个 Find 方法。您可以将 Location 类视为我的“聚合根”。
如果不使用抽象类,这就是我的存储库合约的样子:
IQueryable<City> FindCities();
IQueryable<State> FindStates();
IQueryable<Country> FindCountries();
....
糟糕!
这就是我的存储库合同目前的样子(我想保持这种方式):
IQueryable<Location> Find();
那么,还有比拥有所有这些联合更好的想法吗?一个可以动态链接多个 IQueryable 的 IQueryable
扩展方法?
请记住,我还有一个执行过滤/收集投影(延迟执行)的服务层。存储库需要返回“查询”,而不是具体的集合。
感谢您的帮助。
I'm working on a .NET 4 application, C#, Entity Framework 4, SQL Server 2008.
I have a 7 tables in my database, each representing a specific level of location (Country, State, City, Neighborhood, etc).
Now in my Repository I am trying to define an interface contract which has only one Find() method. To do this, I've created an abstract class called "Location" for which the POCO locations all inherit from.
Here's the method I currently have:
public IQueryable<Location> Find()
{
return AllCountries()
.Union(AllStates())
.Union(AllCounties())
.Union(AllCities())
.Union(AllNeigbourhoods())
.Union(AllZipCodes())
.Union(AllStreets());
}
Those inline methods (e.g AllStates) are private IQueryable methods, e.g:
private IQueryable<Location> AllCountries()
{
var db = new MyCustomDataContext();
return db.Countries;
}
This all works fine, but I don't like the look of the code in the Find() method.
Essentially, I want a Repository method which returns all Countries/Cities/States etc (as an IQuerable<Location>
).
That way, my service layer can do this:
var countries = repository.Find(somePredicate).OfType<Country>().ToList();
Or this:
var countries = repository.Find(somePredicate).OfType<City>().ToList();
So I only ever have to declare one Find method. You can think of the Location class as my "aggregate root".
Without using an abstract class, this is what my repository contract would look like:
IQueryable<City> FindCities();
IQueryable<State> FindStates();
IQueryable<Country> FindCountries();
....
Yuck!
This is what my repository contract currently looks like (and I want to keep it this way):
IQueryable<Location> Find();
So, any better ideas than having all those union's? An IQueryable<T>
extension method which can dynamically chain on multiple IQueryable's?
Remembering I also have a Service Layer which performs the filtering/collection projection (delayed execution). The repository needs to return "queries", not concrete collections.
Appreciate the help.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我假设相同的逻辑实体不会存在于两个单独的表中(例如,“城市”不是“州”)。在这种情况下,您更适合使用
Concat
而不是Union
。一个简短的帮助方法将使调用看起来更好(警告:未经测试):
I'm assuming that the same logical entity won't exist in two separate tables (e.g., a "city" is not a "state"). In that case, you'd be better suited to use
Concat
rather thanUnion
.A brief helper method will make the call look nicer (warning: untested):
实体框架允许您将表映射到使用继承的数据模型。如果数据库中有一个包含所有公共字段的
Location
表,并且每个子位置类(例如City
)都有该的外键Location
表,那么当您从存储库检索Location
对象时,您还应该接收继承类的实例。如果
Location
中没有公共字段,那么拥有联合集合似乎没有什么好处。The Entity Framework allows you map your tables to a data model that uses inheritance. If you had a
Location
table in your database containing all of your common fields, and each sub-location class (such asCity
) had a foreign key to thatLocation
table, then when you retrieveLocation
objects from the repository, you should also receive instances of the inherited classes.If there are no common fields within
Location
, then there seems to be little benefit to having a unioned collection.