【问题标题】:Entity Framework 6 navigation property loading not working实体框架 6 导航属性加载不起作用
【发布时间】:2015-12-04 20:23:18
【问题描述】:

被这个奇怪的问题困扰了好几个小时。由于某种原因,实体框架不会加载这种一对多关系的导航属性,即使生成的 SQL 似乎是正确的,从 SubItems 到 FrontPageItems 存在外键:

CONSTRAINT [FK_dbo.SubItems_dbo.FrontPageItems_FrontPageItemId] 
    FOREIGN KEY ([FrontPageItemId]) 
        REFERENCES [dbo].[FrontPageItems] ([Id]) ON DELETE CASCADE

我已尝试使用以下方式加载所有首页项目: _repo.Get();,但即使 SubItem 表包含引用 FronPageItems 表的外键,也不会加载导航属性。

public class FrontPageItem : Logger, IEntity, IIsPublished
{
    public FrontPageItem()
    {
        SubItems = new HashSet<SubItem>();
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public bool IsPublished { get; set; }
    public virtual ICollection<SubItem> SubItems { get; set; }
}

    public class SubItem : Logger, IEntity, IIsPublished
{
    public SubItem()
    {
        FrontPageItem = new FrontPageItem();
    }
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public string YoutubeUrl { get; set; }
    public virtual FrontPageItem FrontPageItem { get; set; }

    public int FrontPageItemId { get; set; }

    public bool IsPublished { get; set; }
}
public class SampleContext : IdentityDbContext<ApplicationUser>
{
    // throwIfV1Schema is used when upgrading Identity in a database from 1 to 2.
    // It's a one time thing and can be safely removed.
    public SampleContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }

    public static SampleContext Create()
    {
        return new SampleContext();
    }

    // Define you conceptual model here. Entity Framework will include these types and all their references. 
    public IDbSet<FrontPageItem> FrontPageItem { get; set; }
    public IDbSet<SubItem> SubItems { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // The DateTime type in .NET has the same range and precision as datetime2 in SQL Server.
        // Configure DateTime type to use SQL server datetime2 instead.
        modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));

        base.OnModelCreating(modelBuilder);
    }
}

顺便说一句,如果我删除 SubItem 中的外键属性,它会起作用:

公共 int FrontPageItemId { 获取;放; }

我尝试过像这样使用 include 进行预加载:

        var frontPageItems = _repo.AsQueryable().Include(o => o.SubItems).ToList();

【问题讨论】:

  • 什么是_repo.Get()?为什么您希望它自动为您加载相关实体?您是否启用了延迟加载?
  • 你在哪里告诉 EF 它应该如何处理你的关系?我缺少类似 HasRequired(si=> si.FrontPageItem) .WithMany(fpi=> fpi.SubItems) .HasForeignKey(si=> si.FrontPageItemId );
  • 我使用约定,它似乎生成了正确的 SQL:CONSTRAINT [FK_dbo.SubItems_dbo.FrontPageItems_FrontPageItemId] FOREIGN KEY ([FrontPageItemId]) REFERENCES [dbo].[FrontPageItems] ([Id]) ON删除级联

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


【解决方案1】:

正如 DavidG 所提到的,延迟加载是默认的 en EF。这意味着只有在您实际使用它们时才会加载这些属性。

为了强制包含子项,您可以像这样使用包含

FrontPageItem.Include(x => x.SubItems).FirstOrDefault().

FrontPageItem 这里是您的数据库集。如果您像这样查询它,它将加载第一个 frontpageitem,其中包含所有连接到它的子项。

更新:如果您严格遵守约定,则不需要这样做,但如果您的属性有不同的名称或想要有一个明确的外键,那么您可以配置外键像这样

modelBuilder.Entity<SubItem>() 
  .HasRequired(t => t.FrontPageItem) 
  .WithMany(t => t.SubItems) 
  .HasForeignKey(d => d.FrontPageItemId) 
  .WillCascadeOnDelete(true);

【讨论】:

  • 似乎约定应该处理这个问题:msdn.microsoft.com/en-us/data/jj679962.aspx 顺便说一句,我尝试了包含技巧。它没有用,如果我删除 public int FrontPageItemId { get; 现在它可以工作了放; } 属性并让 EF 为我生成这个外键
  • 你是对的 whitelatino,我更新了我的答案。如果您想指定自己的外键而不是让 EF 为您生成它,则可以使用模型构建器部分。否则约定应该为你处理它。
  • 顺便说一句 _repo 是一个通用存储库tugberkugurlu.com/archive/… 对不起,我尝试了所有这些但没有奏效。我已经在 google 上阅读了关于此的热门帖子,似乎没有任何东西可以解释为什么我的外键属性让我无法加载导航属性。
  • 如果您的特定代码不起作用,也许您可​​以更新问题。如果它是一个通用存储库,您能否准确地向您展示您尝试过的包含技巧?
  • 我已经更新了,为了清楚起见,当我没有在 SubItems 中声明外键属性时,这一切都有效,这是一个很大的谜团。它甚至可以在 serverexplore 中使用,因为我无法在 FrontPageItems 上选择不存在的 SubItemId。
【解决方案2】:

LazyLoadingEnabled 必须为真,不能为假:

context.Configuration.LazyLoadingEnabled = true; 如果您根本没有设置 LazyLoadingEnabled,则 true 是默认值。

并且SubItems 属性必须是虚拟的才能启用此属性的延迟加载。

或者您可以直接在查询中包含该属性。 您还需要使用modelBuilder 设置FK

    modelBuilder.Entity<SubItem>() 
  .HasRequired(t => t.FrontPageItem) 
  .WithMany(t => t.SubItems) 
  .HasForeignKey(d => d.FrontPageItemId) 
  .WillCascadeOnDelete(true);

或者通过使用属性配置关系

[ForeignKey("FrontPageItem")]
 public virtual FrontPageItem FrontPageItem { get; set; }

【讨论】:

  • 对不起,我的约定与您的流利的 api 语句/数据注释完全相同。
【解决方案3】:
    public SubItem()
{
    FrontPageItem = new FrontPageItem();
}

是问题所在。出于某种原因,SubItem 中的构造函数被创建为这种奇怪的行为,其他一切都很好。

【讨论】:

  • 构造函数有什么问题?不知道我理解你所说的“是问题所在”是什么意思......
  • 删除此构造函数使我能够加载导航属性。
  • 嗯,好的。这很有趣,我希望一些 EF 专家可以解释为什么这样的构造函数会禁用导航属性加载。我想它可能会覆盖 EF 的一些默认行为,但我想知道 EF 实现如何工作的细节。为什么还要初始化主体对象?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多