2009-01-20 60 views
2

我有一个我想与LinqToSql查询层次:如何使用LinqToSQL查询层次结构?

国家 - >区域 - >市 - >邮编

每个实体都持有对它的引用的父(如Region.Country)和它的孩子的集合(例如Region.Cities)。

我想加载每个实体的父母以及国家和地区,但延迟加载城市和邮政编码。

使事情复杂化,每个实体在投影到模型之前都已被本地化。所以Country.Name根据语言而改变。

这里是什么,我至今一些片段:

public IQueryable<Country> ListCountries() 
{ 
    return ProjectCountry(dataContext.GetTable<ec_Country>()); 
} 

private IQueryable<Country> ProjectCountry(IQueryable<ec_Country> query) 
{ 
    var result = from country in query 
    join localized in dataContext.GetTable<ec_CountryLocalization>() on country.CountryID equals localized.CountryID 
    let regions = GetRegions(country.CountryID) 
    where localized.StatusID == 4 && localized.WebSiteID == this.webSiteID 
    select new Country(country.CountryID) { 
    CreatedDate = country.CreatedDate, 
    IsDeleted = country.IsDeleted, 
    IsoCode = country.IsoCode, 
    Name = country.Name, 
    Regions = new LazyList<Region>(regions), 
    Text = localized.Text, 
    Title = localized.Title, 
    UrlKey = country.UrlKey 
    }; 

    return result; 
} 

private IQueryable<Region> GetRegions(Int32 countryID) 
{ 
    var query = from r in dataContext.GetTable<ec_Region>() 
    where r.CountryID == countryID 
    orderby r.Name 
    select r; 

    return ProjectRegion(query); 
} 

private IQueryable<Region> ProjectRegion(IQueryable<ec_Region> query) 
{ 
    var result = from region in query 
    join localized in dataContext.GetTable<ec_RegionLocalization>() on region.RegionID equals localized.RegionID 
    join country in ListCountries() on region.CountryID equals country.CountryID 
    let cities = GetCities(region.RegionID) 
    select new Region(region.RegionID) { 
    Cities = new LazyList<City>(cities), 
    Country = country, 
    CountryID = region.CountryID, 
    CreatedDate = region.CreatedDate, 
    IsDeleted = region.IsDeleted, 
    IsoCode = region.IsoCode, 
    Name = region.Name, 
    Text = localized.Text, 
    Title = localized.Title, 
    UrlKey = region.UrlKey 
    }; 

    return result; 
} 

...等

[TestMethod] 
public void DataProvider_Correctly_Projects_Country_Spike() 
{ 
    // Act 
    Country country = dataProvider.GetCountry(1); 

    // Assert 
    Assert.IsNotNull(country); 
    Assert.IsFalse(String.IsNullOrEmpty(country.Description)); 
    Assert.IsTrue(country.Regions.Count > 0); 
} 

测试失败:

System.NotSupportedException:方法体系。 Linq.IQueryable`1 [Beeline.EducationCompass.Model.Region] GetRegions(Int32)'不支持对SQL的转换。

你会如何推荐我去做这件事?如果层次结构的每个层次都在同一个表中而不是单独的表中,它会更简单(或可能)吗?

回答

2

您将要使用linq设计器来设置您的对象之间的关系。这通过创建属性让您在加入后在加入后编写加入。

    一个国家和地区
  • 区域和城市的国家,它的本地化
  • 之间
  • 区域和本地化

你会之间之间

  • 想要使用ToList来分离您打算转换为SQL的操作,以及您打算在本地代码中完成的操作。如果你不这样做,你会看到那些“不能将你的方法转换成SQL”的例外。

    你也想用DataLoadOptions在某些情况下急切地加载这些属性。这是我的刺伤。

    DataLoadOptions dlo = new DataLoadOptions(); 
    //bring in the Regions for each Country 
    dlo.LoadWith<ec_Country>(c => c.Regions); 
    //bring in the localizations 
    dlo.AssociateWith<ec_Country>(c => c.Localizations 
        .Where(loc => loc.StatusID == 4 && loc.WebSiteID == this.webSiteID) 
    ); 
    dlo.AssociateWith<ec_Region>(r => r.Localizations); 
    
    //set up the dataloadoptions to eagerly load the above. 
    dataContext.DataLoadOptions = dlo; 
    
    //Pull countries and all eagerly loaded data into memory. 
    List<ec_Country> queryResult = query.ToList(); 
    
    //further map these data types to business types 
    List<Country> result = queryResult 
        .Select(c => ToCountry(c)) 
        .ToList(); 
    

    public Country ToCountry(ec_Country c) 
    { 
        return new Country() 
        { 
        Name = c.Name, 
        Text = c.Localizations.Single().Text, 
        Regions = c.Regions().Select(r => ToRegion(r)).ToList() 
        } 
    } 
    
    public Region ToRegion(ec_Region r) 
    { 
        return new Region() 
        { 
        Name = r.Name, 
        Text = r.Localizations.Single().Text, 
        Cities = r.Cities.Select(city => ToCity(city)).ToLazyList(); 
        } 
    } 
    
  • +0

    谢谢!这看起来很有希望。明天我会试一试。 – 2009-01-26 23:30:57

    1

    这是一个粘性一段代码,而我不会回答这种由于缺乏相关的技能,如果任何人都有的,但因为你没有反应......

    我可以告诉你什么错误消息的意思。这意味着函数GetRegions不能被linq to sql提供者翻译成sql。一些内置函数可以是,因为提供者理解它们,这里是list。否则,您可以提供翻译,请参阅here

    在你的情况下,你需要'内联'这个查询的逻辑,逻辑不会越过函数调用的边界,因为你正在处理表达式树,sql服务器不能回调成你的GetRegions方法。至于确切的做法,你必须有一个去,我现在没有时间强迫你。 (除非别人有时间和技巧?)

    祝你好运。