2009-01-20 34 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方法。至於確切的做法,你必須有一個去,我現在沒有時間強迫你。 (除非別人有時間和技巧?)

    祝你好運。