我有一个带有EF Core 2.1的ASP.NET Core Web API。
这些是我的(简化的)实体。
public class Application
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<ApplicationDiscipline> ApplicationDisciplines { get; set; }
}
public class Discipline
{
public int Id { get; set; }
public ICollection<ApplicationDiscipline> ApplicationDisciplines { get; set; }
public ICollection<DisciplineTranslation> DisciplineTranslations { get; set; }
}
public class ApplicationDiscipline
{
public int ApplicationId { get; set; }
public Application Application { get; set; }
public int DisciplineId { get; set; }
public Discipline Discipline { get; set; }
}
public class DisciplineTranslation {
public int DisciplineId { get; set; }
public Discipline Discipline { get; set; }
public string TranslatedDisciplineName { get; set; }
public string TranslatedDisciplineDescription { get; set; }
public int LanguageId { get; set; }
public Language { get; set; }
}
public class Language
{
public string Name { get; set; }
public string Key { get; set; }
}
因此Application
和Discipline
之间有很多对,Discipline
和DisciplineTranslation
之间有许多。
现在,我想使用两个参数查询数据库:ApplicationName
和LanguageKey
。
我似乎无法弄清楚如何用其学科和相应学科翻译来查询正确的应用程序。我想到的唯一一件事就是在[NotMapped] ICollection<Disciplines> Disciplines
上添加一个Application
并使用此查询。
var application = await Table
.Include(a => a.ApplicationDisciplines)
.Where(x => x.Name.Equals(appName, StringComparison.InvariantCultureIgnoreCase))
.Select(a => new Application()
{
Id = a.Id,
Name = a.Name,
Disciplines = a.ApplicationDisciplines
.Select(ad => new Discipline()
{
Id = ad.Discipline.Id,
DisciplineTranslations = ad.Discipline
.DisciplineTranslations
.Where(dt => dt.Language
.Key.Equals(languageKey, StringComparison.InvariantCultureIgnoreCase))
.ToList()
})
})
.FirstOrDefaultAsync();
如果不需要EF Core ApplicationDiscipline
,这将非常容易。
哪些LINQ查询将在不将ICollection<Discipline> Disciplines
添加到Application
的情况下完成该工作?
答案 0 :(得分:1)
就获得Application
作为最终结果而言,一个选择是
包含所有内容-不太好:
这看起来与
var x = await Table.Include(a=> a.ApplicationDisciplines).ThenInclude(a=> a.Discipline).ThenInclude(a=> a.DisciplineTranslations).ThenInclude(a=> a.Language).Where( a=> a.Name == appName && a.Any(b=> b.Discipline.DisciplineTranslations.Any(c=> c.Language.Key == languageKey))).FirstOrDefaultAsync()
尽管尚未通过.Any()
操作进行链接,但我尚未进行测试。我知道您可以将其链接到两个级别,但是未经测试就可以进行额外的测试。
我会说这是一个不好的方法,因为它可能导致整体查询非常缓慢。
使用联接:总体上可能是更好的解决方案
var aThing = ApplicationDisciplineTable.Include(x=> x.Application).Include(x=> x.Discipline).Where(x=> x.Application.Name == appName).ToList().Join(DisciplineTranslationTable.Include(x=> x.Language).Where(x=> x.Language.Key == appKey), AppDis => AppDis.DisciplineId, DisTrans => DisTrans.DisciplineId, (AppDis, DisTrans) => new {whatever details you want in here}).FirstOrDefault();
因此,连接看起来并不十分干净,您可以最后只选择一个应用程序,其中包含所需的确切详细信息,因为您确实拥有所需的一切。但这是直接在已过滤掉的中间对象上使用联接,因此最终只会得到一个唯一符合条件的学科,应用程序和语言
答案 1 :(得分:0)
通过使用Select()
,我可以过滤到DisciplineTranslations
。
var application = await Table.Include(a => a.ApplicationDisciplines)
.ThenInclude(x => x.Discipline)
.Where(x => x.Name.Equals(appName, StringComparison.InvariantCultureIgnoreCase))
.Select(x => new Application(){
Id = x.Id,
Name = x.Name,
ApplicationDisciplines = x.ApplicationDisciplines.Select(y =>
new ApplicationDiscipline() {
ApplicationId = y.ApplicationId,
Application = y.Application,
DisciplineId = y.Discipline.Id,
Discipline = new Discipline() {
Id = y.Discipline.Id
DisciplineTranslations = y.Discipline.DisciplineTranslations.Where(z => z.Language.Key == languageKey).ToList()
}
})
}).SingleOrDefaultAsync();
通过使用SQL Server Profiler,我们注意到了一次故障。
在我们的情况下,一个应用程序(仅)有4个Disciplines
,因此EF Core执行1个查询以获取Application
,并执行4个查询以获取DisciplineTranslations
。因此,仍有改进的空间。