簡體   English   中英

EF Core 一對多雙向導航不起作用

[英]EF Core One To Many both way navigation is not working

我在 .NET 內核上工作,API 和 EF-CORE

我創建了 DTO 以在 UI 端顯示它。 我正在過濾該 dto 的數據。 問題是我不能為每個表使用兩種導航屬性

我將在兩個例子中解釋我的問題作為一個例子。

假設我有兩個像這樣的 model:

public class Blog
    {
        public int BlogId { get; set; }
        public string Url { get; set; }
        public List<Post> Posts { get; set; }
    }
 public class Post
    {
        public int PostId { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }
        public Blog Blog { get; set; }
        public int BlogId { get; set; }
    }

然后我正在創建查詢:

這是工作:

 var query = await _context.Posts
               .Include(c => c.Blog)
               .Select(c => new DenemeDto
               {
                   DenemeName=c.Title
               }).ToListAsync();

這是行不通的:

var query = await _context.Blogs
               .Include(c => c.Posts)
               .Select(c => new DenemeDto
               {
                   DenemeName=c.Title
               }).ToListAsync();
            return Ok(query);

創建方法:

modelBuilder.Entity("Entities.Concrete.Blog", b =>
                {       b.Property<int>("BlogId")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("int");      
        SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("BlogId"), 1L, 1);
                    b.Property<string>("Url")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");
                    b.HasKey("BlogId");
                    b.ToTable("Blogs");});




modelBuilder.Entity("Entities.Concrete.Post", b =>
                {       b.Property<int>("PostId")
                        .ValueGeneratedOnAdd()
                        .HasColumnType("int");   
             SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property<int>("PostId"), 1L, 1);
                    b.Property<int>("BlogId")
                        .HasColumnType("int");
                    b.Property<string>("Content")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");
                    b.Property<string>("Title")
                        .IsRequired()
                        .HasColumnType("nvarchar(max)");
                    b.HasKey("PostId");
                    b.HasIndex("BlogId");
                    b.ToTable("Posts"); });

我想知道為什么?

親切的問候...

您的假設對Include的作用有些困惑。

var query = await _context.Posts
    .Include(c => c.Blog)
    .Select(c => new DenemeDto
    {
        DenemeName=c.Title
    }).ToListAsync();

Include意味着“急切地加載這個親戚”。 當您想要返回實體以便它們的相關實體與它們一起加載時,這適用。 通常,這可能是您正在加載單個博客並想要訪問其帖子的情況:

var blog = await _context.Blog
    .Include(b => b.Posts)
    .SingleAsync(b => b.BlogId == blogId);

如果沒有Include ,EF 將加載博客,但如果您嘗試訪問它下面的帖子,這將觸發延遲加載(如果啟用)或者只是 #null 或空集合。 延遲加載是一個有用的功能,但會帶來巨大的成本。 如果您知道您將需要相關數據,您可以使用Include加載它。

當您使用Select時,您正在做一些不需要急切加載的投影。 EF 將構建一個適合獲取您請求的數據的查詢。 因此,您的查詢可以簡化為:

var query = await _context.Posts
    .Select(c => new DenemeDto
    {
        DenemeName=c.Title
    }).ToListAsync();

這有效地轉化為:“從帖子中選擇標題”,當它返回時,EF 將填充 DenemeDto 模型。

所以看看你的第二個例子:

var query = await _context.Blogs
    .Include(c => c.Posts)
    .Select(c => new DenemeDto
    {
        DenemeName=c.Title
    }).ToListAsync();

同樣, Include在這里什么也不做,因此您的查詢將轉換為:

“從博客中選擇標題”

如果博客沒有 Title 屬性,這將導致編譯時投訴,或者給你博客的標題,而不是你的帖子。

如果您的帖子沒有對博客的引用,並且您只有 Blog.Posts 可以使用並想要帖子標題:

var query = await _context.Blogs
    .SelectMany(c => Posts
        .Select( p => new DenemeDto
        {
            DenemeName=c.Title
        }).ToList())
   .ToListAsync(); 

如果您想要 select 博客,但要計算他們的帖子數,則投影如何處理關系的一個更好的例子是:

var query = await _context.Blogs
    .Select( b => new BlogDto
    {
        BlogName = b.Title
        PostCount = b.Posts.Count()
    }).ToListAsync(); 

如果我們加載實體,我們會將每個博客和每個帖子加載到 memory 中,只是為了獲取這些信息。 使用上述查詢,EF 將構建一個查詢,該查詢僅返回博客名稱和每個博客的帖子計數。 更快,並且注意我們不需要擔心急切或延遲加載的成本。

在讀取數據時,投影絕對是一個有用的工具,因為它可以幫助 EF 構建更高效的查詢。 急切地加載大量相關數據會創建笛卡爾積,從而導致大量數據從數據庫返回到服務器,然后 EF 必須將其縮減為實體模型。 這需要時間,memory,在許多情況下還需要帶寬。 Select意味着 EF 可以構建更簡潔的查詢並可能利用數據庫上的索引來節省時間、memory 和帶寬。

在您提供的此示例中:

var query = await _context.Blogs
           .Include(c => c.Posts)
           .Select(c => new DenemeDto
           {
               DenemeName=c.Title
           }).ToListAsync();
        return Ok(query);

cBlog ,所以沒有Title

我不確定您查詢的目的是什么,但如果您想獲取博客的所有帖子,您可以這樣做:

var query = await _context.Blogs
                          .SelectMany(x => x.Posts)
                          .Select(x => new DenemeDto
                          {
                              DenemeName = x.Title
                          })
                          .ToListAsync();

此外,由於您正在對非實體執行Select ,因此您不需要使用Include

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM