Linq 最有效的实体框架代码第一种使用特定子实体展平/投影父实体的方法
我有一个具有核心成员的父实体Linq 最有效的实体框架代码第一种使用特定子实体展平/投影父实体的方法,linq,ef-code-first,entity-framework-5,code-first,Linq,Ef Code First,Entity Framework 5,Code First,我有一个具有核心成员的父实体小部件,以及多个具有语言翻译成员的WidgetTranslation子实体,即说明文本,可提供英语、法语、德语等 e、 g 给定languageId我从 DbSet.Select(w => new TranslatedWidget { Id = w.Id, Code = w.Code, LanguageId = w.LanguageId, Name = w.WidgetTranslations.First(wt=>wt.
小部件
,以及多个具有语言翻译成员的WidgetTranslation
子实体,即说明
文本,可提供英语、法语、德语等
e、 g
给定languageId
我从
DbSet.Select(w => new TranslatedWidget
{
Id = w.Id,
Code = w.Code,
LanguageId = w.LanguageId,
Name = w.WidgetTranslations.First(wt=>wt.LanguageId == languageId).Name,
Description = w.WidgetTranslations.First(wt=>wt.LanguageId == languageId).Description,
Summary = w.WidgetTranslations.First(wt=>wt.LanguageId == languageId).Summary
});
但我觉得这样做效率很低,而且无法在widgetranslation
上扩展更多属性
谢谢我会将
名称
、说明
和摘要
移动到您的数据的嵌套类中
public class TranslatedWidgetTranslation
{
public string Name { get; set; }
public string Description { get; set; }
public string Summary { get; set; }
}
public class TranslatedWidget
{
public int Id { get; set; }
public string Code { get; set; }
public int LanguageId { get; set; }
public TranslatedWidgetTranslation Translation { get; set; }
}
然后,您可以投影到该类中,并且只需要一次第一次
,这将在SQL中只产生一个TOP(1)
子查询,而不是三个子查询:
DbSet.Select(w => new TranslatedWidget
{
Id = w.Id,
Code = w.Code,
LanguageId = languageId,
Translation = w.WidgetTranslations
.Where(wt => wt.LanguageId == languageId)
.Select(wt => new TranslatedWidgetTranslation
{
Name = wt.Name,
Description = wt.Description,
Summary = wt.Summary
})
.FirstOrDefault()
});
您必须在此处使用First或default
,LINQ到实体投影中不支持First
如果不希望使用该嵌套类型,可以先将其投影为匿名类型,然后再转换为最终类,但代码会稍长一些:
DbSet.Select(w => new
{
Id = w.Id,
Code = w.Code,
LanguageId = languageId,
Translation = w.WidgetTranslations
.Where(wt => wt.LanguageId == languageId)
.Select(wt => new
{
Name = wt.Name,
Description = wt.Description,
Summary = wt.Summary
})
.FirstOrDefault()
})
.AsEnumerable()
.Select(x => new TranslatedWidget
{
Id = x.Id,
Code = x.Code,
LanguageId = x.LanguageId,
Name = x.Translation != null ? x.Translation.Name : null,
Description = x.Translation != null ? x.Translation.Description : null,
Summary = x.Translation != null ? x.Translation.Summary : null
});
使用SelectMany通过单个连接展平结构:
var widgetQuery = from w in dbSet.Widgets
from wt in w.WidgetTranslations
where wt.Language == languageId
select new TranslatedWidget
{
Id = w.Id,
Code = w.Code,
LanguageId = w.LanguageId,
Name = wt.Name,
Description = wt.Description,
Summary = wt.Summary
});
我在这里假设,对于给定语言中的每个小部件,您只有一个翻译。谢谢。我很少看到回答者投票支持其他人的答案。谢谢Jim,生成的EF SQL更干净。@JimWooley您提到要使用SelectMany,但您的示例仅适用于SelectMany-我遗漏了什么吗?在封面下,来自。。。语法从转换为
。选择many
。
DbSet.Select(w => new
{
Id = w.Id,
Code = w.Code,
LanguageId = languageId,
Translation = w.WidgetTranslations
.Where(wt => wt.LanguageId == languageId)
.Select(wt => new
{
Name = wt.Name,
Description = wt.Description,
Summary = wt.Summary
})
.FirstOrDefault()
})
.AsEnumerable()
.Select(x => new TranslatedWidget
{
Id = x.Id,
Code = x.Code,
LanguageId = x.LanguageId,
Name = x.Translation != null ? x.Translation.Name : null,
Description = x.Translation != null ? x.Translation.Description : null,
Summary = x.Translation != null ? x.Translation.Summary : null
});
var widgetQuery = from w in dbSet.Widgets
from wt in w.WidgetTranslations
where wt.Language == languageId
select new TranslatedWidget
{
Id = w.Id,
Code = w.Code,
LanguageId = w.LanguageId,
Name = wt.Name,
Description = wt.Description,
Summary = wt.Summary
});