C# - 实体框架代码优先,延迟加载不起作用

Posted

技术标签:

【中文标题】C# - 实体框架代码优先,延迟加载不起作用【英文标题】:C# - Entity Framework Code first, lazy loading not working 【发布时间】:2020-12-11 08:23:42 【问题描述】:

我在使用 SQL Server 数据库的 Entity Framework 6 代码优先方面存在一些问题。 我有一个现有的数据库,我想将它们与实体框架一起使用。在 Visual Studio 2017 中,我添加了一个 ADO.NET 实体数据模型类型的新项目,以首次生成代码优先类。

一旦生成了类,我就开始使用对象与数据库进行交互。这里我有一些延迟加载的问题。一些导航属性为空。导航属性标有virtual,延迟加载和ProxyCreationEnabled为真。

这些屏幕截图说明了问题:

我可以分享 Visual Studio 生成的类:

public partial class ETRFContext : DbContext

    static string conn = "My connection string";

    public ETRFContext() : base(conn)
    
    

    public virtual DbSet<Acessos> Acessos  get; set; 
    public virtual DbSet<Caracteristicas> Caracteristicas  get; set; 
    public virtual DbSet<CircuitoAprovacoes> CircuitoAprovacoes  get; set; 
    public virtual DbSet<EstadosEstudo> EstadosEstudo  get; set; 
    public virtual DbSet<Estudos> Estudos  get; set; 
    public virtual DbSet<GruposAcesso> GruposAcesso  get; set; 
    public virtual DbSet<HistoricoDetalhadoEstudo> HistoricoDetalhadoEstudo  get; set; 
    public virtual DbSet<MembrosGruposAcesso> MembrosGruposAcesso  get; set; 
    public virtual DbSet<Normas> Normas  get; set; 
    public virtual DbSet<Paises> Paises  get; set; 
    public virtual DbSet<PrecedenciasEstudos> PrecedenciasEstudos  get; set; 
    public virtual DbSet<PrecedenciasProgramas> PrecedenciasProgramas  get; set; 
    public virtual DbSet<Programas> Programas  get; set; 
    public virtual DbSet<Projetos> Projetos  get; set; 
    public virtual DbSet<RegistosCAD> RegistosCAD  get; set; 
    public virtual DbSet<TiposEstadoEstudo> TiposEstadoEstudo  get; set; 
    public virtual DbSet<TiposMensagem> TiposMensagem  get; set; 
    public virtual DbSet<TiposProjeto> TiposProjeto  get; set; 

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    
        modelBuilder.Entity<Caracteristicas>()
            .Property(e => e.Chave)
            .IsFixedLength();

        modelBuilder.Entity<Caracteristicas>()
            .Property(e => e.Valor)
            .IsFixedLength();

        modelBuilder.Entity<Estudos>()
            .HasMany(e => e.EstadosEstudo)
            .WithRequired(e => e.Estudos)
            .HasForeignKey(e => e.idEstudo);

        modelBuilder.Entity<Estudos>()
            .HasMany(e => e.HistoricoDetalhadoEstudo)
            .WithRequired(e => e.Estudos)
            .HasForeignKey(e => e.idEstudo);

        modelBuilder.Entity<Estudos>()
            .HasMany(e => e.PrecedenciasEstudos)
            .WithRequired(e => e.Estudos)
            .HasForeignKey(e => e.idEstudo);

        modelBuilder.Entity<Estudos>()
            .HasMany(e => e.PrecedenciasEstudos1)
            .WithRequired(e => e.Estudos1)
            .HasForeignKey(e => e.idEstudoPrecedencia)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Estudos>()
            .HasMany(e => e.RegistosCAD)
            .WithRequired(e => e.Estudos)
            .HasForeignKey(e => e.idEstudo);

        modelBuilder.Entity<GruposAcesso>()
            .HasMany(e => e.Acessos)
            .WithRequired(e => e.GruposAcesso)
            .HasForeignKey(e => e.idGruposAcesso);

        modelBuilder.Entity<GruposAcesso>()
            .HasMany(e => e.MembrosGruposAcesso)
            .WithRequired(e => e.GruposAcesso)
            .HasForeignKey(e => e.idGrupoAcesso);

        modelBuilder.Entity<Paises>()
            .HasMany(e => e.Projetos)
            .WithOptional(e => e.Paises)
            .HasForeignKey(e => e.id_Pais);

        modelBuilder.Entity<Programas>()
            .HasMany(e => e.Acessos)
            .WithRequired(e => e.Programas)
            .HasForeignKey(e => e.idPrograma);

        modelBuilder.Entity<Programas>()
            .HasMany(e => e.CircuitoAprovacoes)
            .WithRequired(e => e.Programas)
            .HasForeignKey(e => e.idPrograma);

        modelBuilder.Entity<Programas>()
            .HasMany(e => e.Estudos)
            .WithRequired(e => e.Programas)
            .HasForeignKey(e => e.idProgramas);

        modelBuilder.Entity<Programas>()
            .HasMany(e => e.PrecedenciasProgramas)
            .WithRequired(e => e.Programas)
            .HasForeignKey(e => e.idProgramaPrecedencia);

        modelBuilder.Entity<Programas>()
            .HasMany(e => e.PrecedenciasProgramas1)
            .WithRequired(e => e.Programas1)
            .HasForeignKey(e => e.idPrograma)
            .WillCascadeOnDelete(false);

        modelBuilder.Entity<Projetos>()
            .HasMany(e => e.Caracteristicas)
            .WithRequired(e => e.Projetos)
            .HasForeignKey(e => e.id_projeto);

        modelBuilder.Entity<Projetos>()
            .HasMany(e => e.Estudos)
            .WithRequired(e => e.Projetos)
            .HasForeignKey(e => e.idProjetos);

        modelBuilder.Entity<TiposEstadoEstudo>()
            .HasMany(e => e.EstadosEstudo)
            .WithRequired(e => e.TiposEstadoEstudo)
            .HasForeignKey(e => e.idEstado);

        modelBuilder.Entity<TiposMensagem>()
            .HasMany(e => e.HistoricoDetalhadoEstudo)
            .WithRequired(e => e.TiposMensagem)
            .HasForeignKey(e => e.idTipoMensagem);

        modelBuilder.Entity<TiposProjeto>()
            .HasMany(e => e.Programas)
            .WithRequired(e => e.TiposProjeto)
            .HasForeignKey(e => e.idTiposProjeto);

        modelBuilder.Entity<TiposProjeto>()
            .HasMany(e => e.Projetos)
            .WithRequired(e => e.TiposProjeto)
            .HasForeignKey(e => e.id_Tipo)
            .WillCascadeOnDelete(false);
    

现在这是Estudos类:

public partial class Estudos

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Estudos()
    
        EstadosEstudo = new HashSet<EstadosEstudo>();
        HistoricoDetalhadoEstudo = new HashSet<HistoricoDetalhadoEstudo>();
        PrecedenciasEstudos = new HashSet<PrecedenciasEstudos>();
        PrecedenciasEstudos1 = new HashSet<PrecedenciasEstudos>();
        RegistosCAD = new HashSet<RegistosCAD>();
    

    public int id  get; set; 
    public int idProjetos  get; set; 
    public int idProgramas  get; set; 

    [Required]
    [StringLength(25)]
    public string NomeEstudo  get; set; 

    [Required]
    [StringLength(5)]
    public string Utilizador  get; set; 

    public DateTime DataInicial  get; set; 

    public DateTime? DataFinal  get; set; 

    public bool Producao  get; set; 

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<EstadosEstudo> EstadosEstudo  get; set; 

    public virtual Programas Programas  get; set; 

    public virtual Projetos Projetos  get; set; 

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<HistoricoDetalhadoEstudo> HistoricoDetalhadoEstudo  get; set; 

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<PrecedenciasEstudos> PrecedenciasEstudos  get; set; 

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<PrecedenciasEstudos> PrecedenciasEstudos1  get; set; 

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<RegistosCAD> RegistosCAD  get; set; 

还有班级Projetos

public partial class Projetos

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public Projetos()
    
        Caracteristicas = new HashSet<Caracteristicas>();
        Estudos = new HashSet<Estudos>();
    

    public int id  get; set; 

    [Required]
    [StringLength(15)]
    public string projeto  get; set; 

    public int id_Tipo  get; set; 

    [StringLength(50)]
    public string Cliente  get; set; 

    [StringLength(50)]
    public string Designacao  get; set; 

    public int? id_Pais  get; set; 

    public int? CalculoEletrico  get; set; 

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Caracteristicas> Caracteristicas  get; set; 

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<Estudos> Estudos  get; set; 

    public virtual Paises Paises  get; set; 

    public virtual TiposProjeto TiposProjeto  get; set; 

我注意到的一件事是,当我在数据库中查询“Estudo”时,我没有得到导航属性“Projetos”,但是当我向数据库询问“Projetos”时,我得到了导航属性“Estudos” ”。

另一件事是,当我在数据库中查询“Estudo”时,我没有获得导航属性“Projetos”,但如果我在数据库中查询 id = Estudo.idProjetos 的“Projetos”,则导航“Estudos”中的“Projetos”属性之前为空,自动填充关联“Projeto”的值。

那么,有人有解决这个问题的技巧吗?

感谢您的帮助。

【问题讨论】:

在查询中使用Include 告诉它您要填充哪些导航属性。 这不是一个最小的例子...... @juharr,是的,这解决了我的问题,非常感谢。但是你可以解释一下为什么在这种情况下我需要把 Include 填满导航属性? @MarcoTeixeira 基本上 EF 不会填充导航属性,除非您告诉它以避免可能更复杂和昂贵的查询。如果我想要的只是一个表中的数据,让它从与它有关系的表中提取所有数据,而这些表与之有关系的表等等可能会使查询花费更长的时间并返回比需要的更多的数据。 【参考方案1】:

在您的Estudos 实体中,您能否将ForeignKey 属性添加到ProgramasProjetos 属性。

[ForeignKey("idProgramas")]
public virtual Programas Programas  get; set; 

[ForeignKey("idProjetos")]
public virtual Projetos Projetos  get; set; 

并且在查询Estudos 时包括ProgramasProjetos

db.Estudos
  .Include(x => x.Programas)
  .Include(x => x.Projetos)
  .ToList();

【讨论】:

以上是关于C# - 实体框架代码优先,延迟加载不起作用的主要内容,如果未能解决你的问题,请参考以下文章

实体框架脚手架和迁移不起作用

实体框架可选的一对一关系不起作用

在 Hibernate / JPA 2.1 中延迟加载的 @OneToOne 映射不起作用?

数据库第一实体框架更新模型不起作用:可能是什么原因?

Vue2 - 路由级别的延迟加载不起作用?

路由的默认 vue-cli 延迟加载代码在定义为 lambda 时不起作用