简体   繁体   English

EFCore 急切加载问题

[英]EFCore eager loading issue

I'm a little bit stumped as to why this is not working in EF Core 3.1.8 and SQLite.我有点困惑为什么这在 EF Core 3.1.8 和 SQLite 中不起作用。 I have a compound foreign key relationship between two entities with an int and Guid.我在两个具有 int 和 Guid 的实体之间有一个复合外键关系。 When I try to eager load all stores with store sections, the StoreSection navigation property is not returning any results.当我尝试使用商店部分预先加载所有商店时,StoreSection 导航属性未返回任何结果。

I've checked the created tables and the data is saving as expected.我检查了创建的表,数据按预期保存。 I've checked the optimized sql generated and when I run it directly, the results return what I expect.我检查了生成的优化的 sql,当我直接运行它时,结果返回我期望的。 Below is a console application demonstrating the problem.下面是一个演示该问题的控制台应用程序。

using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;

namespace TestEfcore
{
    class Program
    {
        static void Main()
        {
            Guid userId = Guid.NewGuid();

            using (var context = new GroceryManagerContext())
            {
                var newStore = new Store
                {
                    Name = "Grocery World",
                    GroceryManagerUserId = userId
                };

                newStore.StoreSections.Add(new StoreSection() { Name = "Deli", GroceryManagerUserId = userId });

                newStore.StoreSections.Add(new StoreSection() { Name = "Produce", GroceryManagerUserId = userId });

                context.Add(newStore);
                context.SaveChanges();
            }
            
            using (var context = new GroceryManagerContext())
            {
                // Attempting to eager load store sections.
                var stores = context.Stores
                   .Include(s => s.StoreSections)
                   .Where(s => s.GroceryManagerUserId == userId)
                   .ToList();

                Console.WriteLine($"The user guid is {userId}.");

                foreach (var store in stores)
                {
                    Console.WriteLine($"There are {store.StoreSections.Count} store sections in {store.Name}.");
                }
            }
        }

        public class Store
        {
            public int StoreId { get; set; }

            public string Name { get; set; } = string.Empty;

            public Guid GroceryManagerUserId { get; set; }

            public List<StoreSection> StoreSections { get; } = new List<StoreSection>();
        }

        public class StoreSection
        {
            public int StoreSectionId { get; set; }

            public string Name { get; set; } = string.Empty;

            public Guid GroceryManagerUserId { get; set; }

            public int StoreId { get; set; }
            public Store Store { get; set; } = new Store();
        }

        public class GroceryManagerContext : DbContext
        {
            public DbSet<Store>? Stores { get; set; }

            public DbSet<StoreSection>? StoreSections { get; set; }

            protected override void OnModelCreating(ModelBuilder builder)
            {
                if (builder == null)
                    throw new ArgumentNullException(nameof(builder));

                base.OnModelCreating(builder);

                builder.Entity<Store>()
                    .HasIndex(s => new { s.Name, s.GroceryManagerUserId })
                    .IsUnique();

                builder.Entity<StoreSection>()
                    .HasIndex(ss => new { ss.Name, ss.GroceryManagerUserId })
                    .IsUnique();

                builder.Entity<StoreSection>()
                    .HasOne(ss => ss.Store)
                    .WithMany(s => s.StoreSections)
                    .HasForeignKey(ss => new { ss.StoreId, ss.GroceryManagerUserId })
                    .HasPrincipalKey(s => new { s.StoreId, s.GroceryManagerUserId })
                    .IsRequired();
            }

            protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
            {
                optionsBuilder.UseSqlite(@"Data Source=D:\src\TestEfcore\TestEfcore\GroceryManager.db");
            }
        }
    }
}

The StoreSections navigation property is not eager loading because you are initializing the Store property on StoreSection entity with the new operator. StoreSections 导航属性不是预先加载,因为您正在使用 new 运算符初始化 StoreSection 实体上的 Store 属性。

This is causing the StoreSection.StoreId property to be saved with a 0 which prevents the association from being created这导致 StoreSection.StoreId 属性被保存为 0,这会阻止创建关联

You'll want to change the StoreSection entity to remove the initialization to resolve the problem:您需要更改 StoreSection 实体以删除初始化以解决问题:

public class StoreSection
{
    public int StoreSectionId { get; set; }

    public string Name { get; set; } = string.Empty;

    public Guid GroceryManagerUserId { get; set; }

    public int StoreId { get; set; }
    public Store Store { get; set; } // initialization has been removed here
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM