【问题标题】:Why EF navigation property return null?为什么 EF 导航属性返回 null?
【发布时间】:2015-05-30 02:56:11
【问题描述】:

我有两个模型 1)

public class Indicator
{
    public long ID { get; set; }
    public string Name { get; set; }
    public int MaxPoint { get; set; }
    public string Comment { get; set; }
    public DateTime DateChanged { get; set; }
    public DateTime DateCreated { get; set; }

    public virtual IList<CalculationType> CalculationTypes { get; set; }
    public virtual IList<TestEntity> TestEntitys { get; set; }
    public virtual IndicatorGroup IndicatorGroup { get; set; }
}

2)

public class CalculationType
{
    public long ID { get; set; }
    public string UnitName { get; set; }
    public int Point { get; set; }
    public DateTime DateCreated { get; set; }
    public DateTime DateChanged { get; set; }

    public virtual Indicator Indicator { get; set; }
    public virtual IList<Сalculation> Calculations { get; set; }
}

我执行这段代码

var indicator = DataContext.Indicators.FirstOrDefault(i => i.ID == indicatorID);
var test = DataContext.CalculationTypes.FirstOrDefault();

导航属性 CalculationTypes 的第一行返回 null

第二行返回空集合。为什么?

更新 快照数据库 项目链接https://github.com/wkololo4ever/Stankin

添加计算

    public class Сalculation
{
    public long ID { get; set; }

    public virtual CalculationType CalculationType { get; set; }
    public virtual ApplicationUser Creator { get; set; }
}

【问题讨论】:

标签: c# asp.net asp.net-mvc entity-framework


【解决方案1】:

1) 是否启用了延迟加载?如果没有,您需要使用“.Include”语法显式加载导航属性。

2) 你确定 EF 应该能够检测到这种关系吗?您使用的是代码优先还是数据库优先?

编辑:3)您确定数据库中有数据,并且从 Indicator 到 IndicatorGroup 的外键具有该特定记录的值吗?我这样说是因为如果根本没有数据,则值“null”是有效的。

附:如果您在指标上没有看到名为“IndicatorGroupId”的外键,则表“IndicatorGroup”上可能有一个“IndicatorId”,在这种情况下 - 从您提供的名称开始 - 您的数据库配置错误,您需要使用流利的语法或数据属性来指导 EF 如何制作外键。

【讨论】:

  • 3) 我在帖子中添加了快照数据库数据。
  • 在我的上下文类中,我没有 context.Configuration.ProxyCreationEnabledcontext.Configuration.LazyLoadingEnabled 属性。这是否意味着它们默认启用?
【解决方案2】:

试试这个:

DbContext.Configuration.ProxyCreationEnabled = true;    
DbContext.Configuration.LazyLoadingEnabled = true;  

如果 DbContext.Configuration.ProxyCreationEnabled 设置为 false,除非在父对象上调用 Include 方法,否则 DbContext 将不会为某些父对象加载子对象。将 DbContext.Configuration.LazyLoadingEnabled 设置为 true 或 false 不会对其行为产生影响。

如果 DbContext.Configuration.ProxyCreationEnabled 设置为 true,子对象将被自动加载,并且 DbContext.Configuration.LazyLoadingEnabled 值将控制何时加载子对象。

我认为这是个问题:

编辑:3) 你确定你的数据库中有数据并且 从 Indicator 到 IndicatorGroup 的外键有一个值 具体记录?我这样说是因为如果值“null”是有效的 根本没有数据。

附:如果您在 Indicator 上没有看到外键调用 “IndicatorGroupId”,表上可能有一个“IndicatorId” “IndicatorGroup”,在这种情况下 - 来自您提供的名称 - 您的数据库配置错误,您需要使用流利的语法 或数据属性来指导 EF 如何制作外键。

试试这个并确保外键被更正。

public class CalculationType
{
    public long ID { get; set; }
    public string UnitName { get; set; }
    public int Point { get; set; }
    public DateTime DateCreated { get; set; }
    public DateTime DateChanged { get; set; }
    [ForeignKey("IndicatorID")]
    public string IndicatorId { get; set; } //this is the foreign key, i saw in your database is: Indicator_ID, avoid this, rename it to IndicatorID or IndicatorId

    public virtual Indicator Indicator { get; set; }
    public virtual IList<Сalculation> Calculations { get; set; }
}

【讨论】:

  • 所有此属性已启用。
  • 我看到第二张图片,它返回空列表,你有数据吗?
  • 我没有这方面的数据。当我在那里有数据时,它们会立即加载。我不明白为什么不工作延迟加载。
  • 您似乎将延迟加载误认为与实际情况相反。延迟加载意味着当您访问导航属性时会自动加载您的数据。
  • If DbContext.Configuration.ProxyCreationEnabled is set to true, child objects will be loaded automatically, and DbContext.Configuration.LazyLoadingEnabled value will control when child objects are loaded. 这根本不是真的。关闭 LazyLoading 后,除非调用 Include(),否则不会加载实体。
【解决方案3】:

行为相同,但根本原因与所选答案不同:

如果关闭myContext.Configuration.AutoDetectChangesEnabled,导航属性也可以为空

非常明显,但这让我在实施一些性能改进时得到了启发。

【讨论】:

  • 它至少解决了我的一些问题。猜测,这种行为也可能出现在某些多线程场景中。
【解决方案4】:

看看这个:Navigation Property With Code First 。其中提到了导航属性为空的原因及其解决方法。

默认情况下,导航属性为空,它们不被加载 默认。对于加载导航属性,我们使用“include”方法 IQuearable,这种类型的加载称为 Eager loading。

急切加载:这是一个查询一种实体类型的过程 加载相关实体作为查询的一部分,它是通过 IQueryable 的“include”方法。

【讨论】:

    【解决方案5】:

    我遇到了这个问题,即没有加载导航属性,即使存在 Include 语句。

    问题是由使用 .NET 的 SQL Server 和 EF6 之间的字符串比较差异引起的。我在customers 表中使用VARCHAR(50) 字段作为主键,并且在audit_issues 表中作为外键字段。我没有意识到我在customers 表中的键末尾有两个额外的空格字符;我的audit_issues 表中没有这些字符。

    However, SQL Server will automatically pad whitespace for string comparisons。这适用于 WHERE 和 JOIN 子句,以及对 FOREIGN KEY 约束的检查。 IE。数据库告诉我字符串是等价的并且约束通过了。因此我假设他们实际上是完全相等的。但那是错误的。一个字段的 DATALENGTH = 10,而另一个字段的 DATALENGTH = 8。

    EF6 将正确组合 SQL 查询以提取外键相关字段,我会在生成的 Sql 查询和结果中看到它们。但是,EF6 在加载导航属性时会静默失败,因为 .NET 不认为这些字符串是相等的。 注意字符串类型外键字段中的空格!.

    【讨论】:

      【解决方案6】:

      这个article 帮助了我。

      总之:

      Install-Package Microsoft.EntityFrameworkCore.Proxies

      Startup.cs

      using Microsoft.EntityFrameworkCore;
      
      public void ConfigureServices(IServiceCollection services)
              {
                    ...
                  services.AddDbContext<MyDbContext>(builder =>
                  {
                      builder.UseLazyLoadingProxies(); // <-- add this
                  }, ServiceLifetime.Singleton);
      

      【讨论】:

      • 这篇博文充满了不准确之处。但即使完全正确,除非有很好的理由,否则我不会启用延迟加载。 IMO 这是一种反模式。 Include 是他们所需要的。
      • 我使用了我找到的另一个变体并将其放入 ContextPartial.cs 文件中(因此 EF 可以重建基本上下文文件而不会丢失我的更改)。 --> public partial class MyTableContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseLazyLoadingProxies(); }
      【解决方案7】:

      这是Keytrap 答案的变体。使用 .NET 6EF Core 6,我为我不希望 EF 的 Scaffold 命令执行的任何自定义配置创建了一个 ContextPartials.cs覆盖:

      需要的包:

      Install-Package Microsoft.EntityFrameworkCore.Proxies
      

      代码(ContextPartials.cs):

      // NOTE:  I am not using the new file-scoped namespace on purpose
      namespace DataAccess.Models.MyDatabase
      {
          // NOTE:  This is a partial outside of the generated file from Scaffold-DbContext
          public partial class MyDatabaseContext
          {
              // NOTE:  This enables foreign key tables to become accessible
              protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
                  => optionsBuilder.UseLazyLoadingProxies();
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-11-07
        • 1970-01-01
        • 2022-09-23
        • 1970-01-01
        • 1970-01-01
        • 2012-11-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多