如何仅在相关实体中包含选定的属性

我只能包含相关实体。

using (var context = new BloggingContext()) { // Load all blogs, all related posts var blogs1 = context.Blogs .Include(b => b.Posts) .ToList(); } 

但是,我不需要整个BlogPost实体。 我只对特定属性感兴趣,例如:

 using (var context = new BloggingContext()) { // Load all blogs, all and titles of related posts var blogs2 = context.Blogs .Include(b => b.Posts.Select(p => p.Title) //throws runtime exeption .ToList(); foreach(var blogPost in blogs2.SelectMany(b => b.Posts)) { Console.Writeline(blogPost.Blog.Id); //I need the object graph Console.WriteLine(blogPost.Title); //writes title Console.WriteLine(blogPost.Content); //writes null } } 

您可以使用加载整个实体的Include ,也可以将您需要的项目投射到.Select

 var blogs2 = context.Blogs .Select(x => new { BlogName = x.BlogName, //whatever PostTitles = x.Post.Select(y => y.Title).ToArray() }) .ToList(); 

或者,你可以这样做:

 var blogs2 = context.Blogs .Select(x => new { Blog = x, PostTitles = x.Post.Select(y => y.Title).ToArray() }) .ToList(); 

当您不需要整个孩子时, Select总是更好,因为它可以防止查询不需要的数据。

实际上你想要的是:在一个共同的,代表性的部分中分割一个实体,一个你并不总是想要从数据库中提取的特殊部分。 这不是一个不常见的要求。 考虑产品和图像,文件及其内容,或拥有公共和私人数据的员工。

entity framework核心支持两种实现此目的的方法:拥有类型和表拆分。

拥有类型

拥有的类型是以另一种类型包装的类型。 它只能通过其所有者访问。 这就是它的样子:

 public class Post { public int ID { get; set; } public Blog Blog { get; set; } public string Title { get; set; } public PostContent Content { get; set; } } public class PostContent { public string Content { get; set; } } 

和拥有类型的映射:

 modelBuilder.Entity().OwnsOne(e => e.Content); 

Blog在哪里

 public class Blog { public Blog() { Posts = new HashSet(); } public int ID { get; set; } public string Name { get; set; } public ICollection Posts { get; set; } } 

但是,根据文档 :

查询所有者时,默认情况下将包含所拥有的类型。

这意味着……

 var posts = context.Posts.ToList(); 

…将始终为您提供post及其内容。 因此,拥有类型可能不适合您。 我仍然提到它,因为我发现当Included Posts时……

 var blogs = context.Blogs.Include(b => b.Posts).ToList(); 

包括所拥有的类型PostContent (免责声明:我不确定这是一个错误还是一个function……)。 在这种情况下,当应包含所拥有的类型时,需要ThenInclude

 var blogs = context.Blogs.Include(b => b.Posts) .ThenInclude(p => p.Content).ToList(); 

因此,如果Post s将始终通过Blog查询,则拥有的类型可能是合适的。

我不认为这适用于此,但是当拥有类型的孩子与其父母有识别关系时(经典示例: Order-OrderLine ),它确实适用。

表拆分

使用表拆分,数据库表将拆分为两个或更多实体。 或者,从对象方面:两个或多个实体映射到一个表。 该模型几乎完全相同。 唯一的区别是PostContent现在有一个必需的主键属性( ID ,当然具有与Post.ID相同的值):

 public class Post { public int ID { get; set; } public Blog Blog { get; set; } public string Title { get; set; } public PostContent Content { get; set; } } public class PostContent { public int ID { get; set; } public string Content { get; set; } } 

表拆分映射:

 modelBuilder.Entity() .HasOne(e => e.Content).WithOne() // or .WithOne(c => c.Post) if there is a back reference .HasForeignKey(e => e.ID); modelBuilder.Entity().ToTable("Posts"); modelBuilder.Entity().ToTable("Posts"); 

现在,默认情况下,将始终查询Post s而不显示其内容。 PostContent应始终显式为Include() PostContent

此外,现在可以在没有其所有者Post情况下查询PostContent

 var postContents = context.Set().ToList(); 

我认为这正是你所寻找的。

当然,如果你想在没有内容的情况下获取post时总是使用投影,那么你可以不用这些映射。

你可以试试这个:

 using (var context = new BloggingContext()) { var blogProps = context.Blogs .SelectMany(b => b.Posts.Select(p => new { Blog = b, PostTitle = p.Title } ) ) .ToList(); } 

编辑
如果你想坚持你的数据模型,你可以尝试这样的事情:

 using (var context = new BloggingContext()) { var blogProps = context.Blogs .Select(b => new Blog { Name = b.Name, Posts = new List(b.Posts.Select(p => new Post { Title = p.Title }) } ) .ToList(); }