如何重构这个IQueryable <t>存储库方法?</t>

时间:2010-08-31 00:26:13

标签: .net linq extension-methods repository-pattern 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()方法中的代码外观。

基本上,我想要一个Repository方法,它返回所有的国家/城市/国家等(作为IQuerable<Location>)。

这样,我的服务层就可以做到这一点:

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<T>扩展方法,可以动态链接多个IQueryable?

记住我还有一个服务层,它执行过滤/收集预测(延迟执行)。存储库需要返回“查询”,而不是具体的集合。

感谢帮助。

2 个答案:

答案 0 :(得分:1)

我假设在两个单独的表中不存在相同的逻辑实体(例如,“city”不是“state”)。在这种情况下,您更适合使用Concat而不是Union

简短的帮助方法将使调用看起来更好(警告:未经测试):

// (Defined in the static class MyHelpers)
// Concatenate all sequences into one.
public IQueryable<T> ConcatAll<T>(this IQueryable<T> first,
    params IQueryable<T>[] others)
{
  var ret = first;
  foreach (var other in others)
  {
    ret = ret.Concat(other);
  }

  return ret;
}

...

public IQueryable<Location> Find() 
{
  return MyHelpers.ConcatAll(
    AllCountries(),
    AllStates(),
    AllCounties(),
    AllCities(),
    AllNeigbourhoods(),
    AllZipCodes(),
    AllStreets());

  // OR:

  return AllCountries().ConcatAll(
    AllStates(),
    AllCounties(),
    AllCities(),
    AllNeigbourhoods(),
    AllZipCodes(),
    AllStreets());
} 

答案 1 :(得分:1)

实体框架允许您将表映射到使用继承的数据模型。如果数据库中有一个包含所有公共字段的Location表,并且每个子位置类(例如City)都有一个指向该Location表的外键,那么从存储库中检索Location个对象,您还应该接收继承类的实例。

如果Location中没有公共字段,那么拥有联合集合似乎没什么好处。