代码之家  ›  专栏  ›  技术社区  ›  Jonathan Moffatt

获取“已尝试在分离实体上延迟加载导航属性”,尽管需要进行快速获取

  •  3
  • Jonathan Moffatt  · 技术社区  · 6 年前

    我正在使用EntityFrameworkCore2.1.2启用延迟加载,并使用AsNoTracking执行查询。我正在使用Include引入我的导航属性(集合)。

    如果我的所有实体在它们的集合中至少有一个子级,那么它们都可以正常工作。

    但是,如果我的任何实体没有子实体,那么我会得到一个错误:

    System.InvalidOperationException异常:为警告生成错误 'Microsoft.EntityFrameworkCore.Infrastructure基础结构.detachedLazyLoading警告: 试图在上延迟加载导航属性“Children” “ParentProxy”类型的分离实体。不支持延迟加载 对于分离的实体或加载了 'AsNoTracking()'。'

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.EntityFrameworkCore;
    
    namespace LazyLoadingIssue
    {
        public class Parent
        {
            public int Id { get; set; }
            public string ParentName { get; set; }
            public virtual ICollection<Child> Children { get; set; }
        }
    
        public class Child
        {
            public int Id { get; set; }
            public int ParentId { get; set; }
            public virtual Parent Parent { get; set; }
            public string ChildName { get; set; }
        }
    
        public class Program
        {
            public static void Main(string[] args)
            {
                SetupDatabase(setupToFail: true);
                PerformTest();
    
                Console.WriteLine("Press any key to finish");
                Console.ReadLine();
            }
    
            private static void PerformTest()
            {
                using (var db = new MyContext())
                {
                    try
                    {
                        IQueryable<Parent> parents = db.Rounds.Include(r => r.Children).AsNoTracking();
                        foreach (Parent parent in parents)
                        {
                            Console.WriteLine($"Parent (Id={parent.Id}) '{parent.ParentName}'");
                            foreach (Child child in parent.Children)
                            {
                                Console.WriteLine($"  - Child (Id={child.Id}, ParentId={child.ParentId}) '{child.ChildName}'");
                            }
                        }
    
                        Console.WriteLine("** WORKED **");
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine("** FAILED **");
                        Console.WriteLine(ex);
                    }
                }
            }
    
            private static void SetupDatabase(bool setupToFail)
            {
                using (var db = new MyContext())
                {
                    db.Database.EnsureDeleted();
                    db.Database.EnsureCreated();
    
                    var parent1 = new Parent
                    {
                        ParentName = "First sample parent (has children)",
                        Children = new List<Child>
                        {
                            new Child {ChildName = "child-1"},
                            new Child {ChildName = "child-2"},
                            new Child {ChildName = "child-3"}
                        }
                    };
                    var parent2 = new Parent
                    {
                        ParentName = $"Second sample parent ({(setupToFail ? "with no children" : "has children")})",
                        Children = new List<Child>()
                    };
                    if (!setupToFail)
                        parent2.Children.Add(new Child {ChildName = "child-4"});
                    db.AddRange(parent1, parent2);
                    db.SaveChanges();
                }
            }
        }
    
    
        public class MyContext : DbContext
        {
            public DbSet<Parent> Rounds { get; set; }
    
            protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
            {
                optionsBuilder
    //                .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=_ModelApp;Trusted_Connection=True;Connect Timeout=5;ConnectRetryCount=0")
                    .UseInMemoryDatabase(databaseName: "_modelApp")
                    .UseLazyLoadingProxies()
                    ;
            }
        }
    
    }
    

    我做错什么了吗?或者这是EF核心的一个bug?(我已经发布了 an issue there

    2 回复  |  直到 6 年前
        1
  •  4
  •   Jonathan Moffatt    6 年前

    为了子孙后代,这里有 response from the EF Core team :

    (10042)但是如果它看起来像 不需要延迟加载。回想起来,最好是 总是扔。请注意,可以将警告配置为不抛出 在DbContextOptionsBuilder中使用ConfigureWarnings。

    为了以防万一,我最后做的是创建第二个“ReadOnlyRepository”,配置为不使用延迟加载并总是返回未跟踪的集。我使用这个存储库进行查询,在这些查询中,我永远不会将更改持久化到任何实体,结果集可能很大,并且需要很好地执行。

    public class ReadOnlyRepository : MainDbContextBase, IReadOnlyRepository
    {
        public ReadOnlyRepository(IConfigurationSettings configurationSettings)
            : base(configurationSettings, false)
        {
        }
    
        public IQueryable<T> Retrieve<T>() where T : class, IAmAnAggregateRoot
        {
            return GetDbSet<T>().AsNoTracking();
        }
    }
    
    public class MainDbContextBase : DbContext
    {
        private readonly IConfigurationSettings configurationSettings;
        private readonly bool useLazyLoading;
    
        protected MainDbContextBase(IConfigurationSettings configurationSettings, bool useLazyLoading)
        {
            this.configurationSettings = configurationSettings;
            this.useLazyLoading = useLazyLoading;
        }
    
        protected DbSet<T> GetDbSet<T>() where T : class
        {
            return Set<T>();
        }
    
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
                optionsBuilder
                    .UseLazyLoadingProxies(useLazyLoading)
                    .UseSqlServer(configurationSettings.ConnectionString);
            }
        }
    
        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            ...
        }
    }
    

        2
  •  0
  •   Robertson Solani Vicente    6 年前

    没有虫子。 由于您没有使用.AsNoTracking跟踪更改,因此延迟加载将永远无法工作。

    推荐文章