C# 如何使用LinqToSQL查询层次结构?
我想用LinqToSql查询一个层次结构: 国家->地区->城市->ZipCode 每个实体既有对其父实体的引用(如Region.Country),也有其子实体的集合(如Region.Cities) 我想急切地加载每个实体的父实体以及国家和地区,但懒得加载城市和邮政编码 使事情复杂化的是,每个实体在投影到模型之前都要进行本地化。所以国家。名称根据语言而变化 以下是我目前掌握的一些信息片段:C# 如何使用LinqToSQL查询层次结构?,c#,linq-to-sql,hierarchy,C#,Linq To Sql,Hierarchy,我想用LinqToSql查询一个层次结构: 国家->地区->城市->ZipCode 每个实体既有对其父实体的引用(如Region.Country),也有其子实体的集合(如Region.Cities) 我想急切地加载每个实体的父实体以及国家和地区,但懒得加载城市和邮政编码 使事情复杂化的是,每个实体在投影到模型之前都要进行本地化。所以国家。名称根据语言而变化 以下是我目前掌握的一些信息片段: public IQueryable<Country> ListCountries() {
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;
}
测试失败,原因是:
System.NotSupportedException:方法'System.Linq.IQueryable'1[Beeline.EducationCompass.Model.Region]GetRegions(Int32)'不支持到SQL的转换
你建议我怎么做?如果层次结构的每个级别都在同一个表中而不是在单独的表中,这会更简单(或可能)吗?这是一段棘手的代码,如果其他人有,我不会回答这个问题,因为缺乏相关技能,但因为你没有回答 我可以告诉您错误消息的含义。这意味着LINQtoSQL提供程序无法将函数GetRegions转换为sql。一些内置函数可以是,因为提供者理解它们,下面是一个例子。否则,您可以提供翻译,请参见 在您的情况下,您需要“内联”此查询的逻辑,该逻辑不会跨越函数调用的边界,因为您处理的是表达式树,sql server无法回调到GetRegions方法中 至于确切的方法,你得试一试,我现在没有时间请你。(除非其他人有时间和技能?)
祝你好运。你需要使用linq设计器来建立对象之间的关系。通过创建属性,您可以避免一次又一次地编写连接
- 在一个国家和地区之间
- 在一个地区和它的城市之间
- 在一个国家和它的地方之间
- 在一个区域和它的局部之间
您将要使用它来分离那些要转换为SQL的操作,以及那些要在本地代码中完成的操作。如果不这样做,您将继续看到那些“无法将您的方法转换为SQL”异常 在某些情况下,您还需要使用来急切地加载这些属性。这是我的尝试
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();
谢谢这看起来很有希望。我明天就试试。这种方法的一种变体很管用。为了避免让LinqToSql对每个地区发出一个查询来获取城市,我必须创建一个ToRegion(ec_region dto)和一个ToRegion允许(ec_region dto)。浅层版本创建模型,但不填充子集合(区域中的城市)。我认为,如果我的数据库使用Joe Celko的嵌套集方法,可能在单个查询中实现这一点。理论上,只需通过一次结果集即可实例化层次结构。还有其他人对此有什么想法吗?
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();
}
}