J'ai une hiérarchie que je voudrais interroger avec LinqToSql:Comment puis-je interroger des hiérarchies avec LinqToSQL?
Pays -> Région -> Ville -> ZipCode
Chaque entité détient à la fois une référence à son parent (. Par exemple Region.Country) et une collection de ses enfants (par exemple Region.Cities). Je voudrais charger avec impatience le parent de chaque entité avec les pays et les régions, mais les villes de chargement paresseux et les codes postaux. Pour compliquer les choses, chaque entité est localisée avant d'être projetée dans le modèle. So Country.Name change en fonction de la langue.
Voici quelques extraits de ce que j'ai jusqu'à présent:
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;
}
... etc.
[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);
}
Le test échoue avec:
System.NotSupportedException: Méthode « Système. Linq.IQueryable`1 [Beeline.EducationCompass.Model.Region] GetRegions (Int32) 'n'a pas de traduction prise en charge vers SQL.
Que recommanderiez-vous de faire? Serait-il plus simple (ou possible) si chaque niveau de la hiérarchie était dans la même table au lieu de ceux séparés?
Merci! Cela semble vraiment prometteur. Je vais essayer demain. –
Une variation de cela a travaillé. Pour éviter que LinqToSql ne lance une requête par région pour obtenir les villes, j'ai dû créer à la fois un ToRegion (ec_Region dto) et un ToRegionShallow (ec_Region dto). La version peu profonde crée le modèle mais ne remplit pas les collections enfants (Villes dans le cas de la Région). –
Je pense que si ma base de données utilisait l'approche Nested Set de Joe Celko, il serait peut-être possible de le faire en une seule requête. Théoriquement, il suffit d'un passage dans le jeu de résultats pour instancier la hiérarchie. Quelqu'un d'autre a des idées à ce sujet? –