从实体框架核心中包含的属性中选择特定属性

Gra*_*Fox 8 entity-framework-core

我使用Entity Framework Core 2.0并拥有这两个类:

新闻

public class News
{
    public int Id { get; set; }
    public string Title{ get; set; }
    public string Text { get; set; }
    public DateTime ReleaseDate{ get; set; }
    public int AuthorID{ get; set; }
    public Author Author{ get; set; }
}
Run Code Online (Sandbox Code Playgroud)

作者

public class Author 
{
    public Author ()
    {
     News = new List<News>();
    }

    public int Id { get; set; }
    public string Username{ get; set; }
    public string Firstname{ get; set; }
    public string Lastname{ get; set; }
    public ICollection<News> News {get;set;}
}
Run Code Online (Sandbox Code Playgroud)

我想用作者的用户名加载新闻,因为我不需要作者的名字和姓氏等其他信息.

如果我执行这个:

static void Main(string[] args)
{
  using (var ctx = new DbContext())
  {
   var result= ctx.News.Include(x => x.Author).Select(news => new
   {
     news= news ,
     Username= pr.Author.Username
   }).ToList();
  }
}
Run Code Online (Sandbox Code Playgroud)

Entity Framework Core 2.0生成一个数据库查询,如:

SELECT [x].[ID], [x].[Text], [x].[Title], [x].[AuthorId], [x].[ReleaseDate], [x.Author].[ID], [x.Verfasser].[Username] AS [Username], [x.Verfasser].[Firstname], [x.Verfasser].[Lastname]
FROM [News] AS [x]
INNER JOIN [Author] AS [x.Author] ON [x].[AuthorId] = [x.Author].[ID]
Run Code Online (Sandbox Code Playgroud)

有没有办法实现我预期的行为?

Iva*_*oev 13

如果我理解正确,您不想加载Author实体(因为没有办法加载实体,只填充了一些非导航属性).

然后问题是为什么你特意添加Include(x => x.Author)请求EF加载Author.Include/ ThenIncludemethods支持热切加载相关数据实体.使用projection(Select)时不需要它们.

有趣的是,EFC 2.0之前的所有EF(Core)版本都忽略了投影类型查询的包含.即使是当前的EFC文档也表明投影查询属于Ignored Includes类别.但是,正如您已经注意到EFC 2.0并没有忽略它!所以它是实现错误,将被修复,或文档错误,并将更新.

目前,根本不要Include在投影查询中使用.如果你执行这个:

var result = ctx.News.Select(news => new
{
    news = news,
    Username = news.Author.Username
}).ToList();
Run Code Online (Sandbox Code Playgroud)

EFC生成的SQL查询现在符合预期:

SELECT [news].[Id], [news].[AuthorID], [news].[ReleaseDate], [news].[Text], [news].[Title], [news.Author].[Username]
FROM [News] AS [news]
INNER JOIN [Authors] AS [news.Author] ON [news].[AuthorID] = [news.Author].[Id] 
Run Code Online (Sandbox Code Playgroud)


Fel*_*lmo 7

您不使用匿名对象,而是创建一个NewsDTO包含要检索的属性的类(示例如下)。

public class NewsDTO
{
    public int Id { get; set; }
    public string Title{ get; set; }
    public string Text { get; set; }
    public DateTime ReleaseDate{ get; set; }
    public string AuthorName { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

然后您可以从存储库层返回一个方法Task<NewsDTO> GetSpecificProperties()

我更喜欢使用AutoMapper,你的代码会更干净:

return context.NewsTable.ProjectTo<NewsDTO>().ToList()
Run Code Online (Sandbox Code Playgroud)

但你可以使用这种奇怪的类型

return context.NewsTable
.Include(x => x.Author)
.Select(x => new NewsDTO
        {
            Id = x.Id.,
            Title = x.Title,
            Text = x.Text,
            ReleaseDate = x.ReleaseDate,
            AuthorName = x.Author.Username
        }).ToList();
Run Code Online (Sandbox Code Playgroud)

Obs:数据库仅在您使用 时检索数据.ToList(),在此之前是 just IQueryable,因此如果您有 where 子句,最好使用 before 检索数据。