Lie*_*ero 7 c# entity-framework-core
我只能包括相关实体。
using (var context = new BloggingContext())
{
// Load all blogs, all related posts
var blogs1 = context.Blogs
.Include(b => b.Posts)
.ToList();
}
Run Code Online (Sandbox Code Playgroud)
但是,我不需要整个 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
}
}
Run Code Online (Sandbox Code Playgroud)
SO *_*ood 11
您可以使用Include
它加载整个实体,或者将您需要的内容投影到.Select
:
var blogs2 = context.Blogs
.Select(x => new
{
BlogName = x.BlogName, //whatever
PostTitles = x.Post.Select(y => y.Title).ToArray()
})
.ToList();
Run Code Online (Sandbox Code Playgroud)
或者,你可以这样做:
var blogs2 = context.Blogs
.Select(x => new
{
Blog = x,
PostTitles = x.Post.Select(y => y.Title).ToArray()
})
.ToList();
Run Code Online (Sandbox Code Playgroud)
Select
当您不需要整个子级时,A总是更好,因为它可以防止查询不需要的数据。
事实上,您想要的是:将实体拆分为公共的、代表性的部分和您并不总是想从数据库中提取的特殊部分。这并不是一个不常见的要求。想想产品和图像、文件及其内容,或者拥有公共和私人数据的员工。
实体框架核心支持两种方式来实现这一点:拥有类型和表拆分。
自有类型是包装在另一种类型中的类型。它只能通过其所有者来访问。它看起来是这样的:
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; }
}
Run Code Online (Sandbox Code Playgroud)
以及拥有类型映射:
modelBuilder.Entity<Post>().OwnsOne(e => e.Content);
Run Code Online (Sandbox Code Playgroud)
哪里Blog
public class Blog
{
public Blog()
{
Posts = new HashSet<Post>();
}
public int ID { get; set; }
public string Name { get; set; }
public ICollection<Post> Posts { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
但是,根据文档:
查询所有者时,默认情况下将包含拥有的类型。
这意味着像这样的声明...
var posts = context.Posts.ToList();
Run Code Online (Sandbox Code Playgroud)
...将始终为您提供帖子及其内容。因此,拥有类型可能不适合您。我还是提到了,因为我发现什么Posts
时候Included
...
var blogs = context.Blogs.Include(b => b.Posts).ToList();
Run Code Online (Sandbox Code Playgroud)
...所拥有的类型PostContent
s 不包括在内(免责声明:我不确定这是错误还是功能...)。在这种情况下,当应包含自有类型时,ThenInclude
需要:
var blogs = context.Blogs.Include(b => b.Posts)
.ThenInclude(p => p.Content).ToList();
Run Code Online (Sandbox Code Playgroud)
因此,如果Post
总是通过 s 查询Blog
s,则拥有的类型可能是合适的。
我不认为这适用于这里,但当拥有自己的类型的孩子与其父母有识别关系时(经典示例:),它就适用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; }
}
Run Code Online (Sandbox Code Playgroud)
以及分表映射:
modelBuilder.Entity<Post>()
.HasOne(e => e.Content).WithOne()
// or .WithOne(c => c.Post) if there is a back reference
.HasForeignKey<PostContent>(e => e.ID);
modelBuilder.Entity<Post>().ToTable("Posts");
modelBuilder.Entity<PostContent>().ToTable("Posts");
Run Code Online (Sandbox Code Playgroud)
现在Post
默认情况下将始终查询 s 而不包含其内容。PostContent
应始终Include()
显式地使用 -ed 。
另外,PostContent
现在可以在没有所有者的情况下进行查询Post
:
var postContents = context.Set<PostContent>().ToList();
Run Code Online (Sandbox Code Playgroud)
我认为这正是您正在寻找的。
当然,如果您想要获取没有内容的帖子时始终使用投影,那么您可以不使用这些映射。
你可以试试这个:
using (var context = new BloggingContext())
{
var blogProps = context.Blogs
.SelectMany(b =>
b.Posts.Select(p =>
new { Blog = b, PostTitle = p.Title }
)
)
.ToList();
}
Run Code Online (Sandbox Code Playgroud)
编辑
如果你想坚持你的数据模型,你可以尝试这样的事情:
using (var context = new BloggingContext())
{
var blogProps = context.Blogs
.Select(b =>
new Blog
{
Name = b.Name,
Posts = new List<Post>(b.Posts.Select(p =>
new Post
{
Title = p.Title
})
}
)
.ToList();
}
Run Code Online (Sandbox Code Playgroud)