【问题标题】:Entity Framework with foreign keys具有外键的实体框架
【发布时间】:2018-10-17 23:02:09
【问题描述】:

简而言之,实体框架应该如何处理相关表。

aspnetcore 2.0

public class Table1{
    [Key]
    public int Id{get;set;}

    [ForeignKey("Table2")]
    public int Table2Id {get;set;}
    public virtual Table2 Table2{get;set;}
}

public class Table2{
    [Key]
    public int Id{get;set;}

}

我假设声明是这样的

var t1 = context.Table1List.FirstOrDefault( j => j.Id == 1)

会自动填充 Table2 但 t1.Table2 为空。

如果我要调用 context.Table2List.FirstOrDe..... 那么即使没有设置属性,也会填充 t1.Table2。所以 EF 认识到这种关系在我实际调用数据库之前不会填充。

我是否理解 EF 是如何工作错误的,或者只是我的代码中的一个错误。也许与延迟加载有关。

我已经阅读了微软的教程,但对它的工作原理和实际工作原理并没有太多了解。

表 1 和表 2 彼此之间只有一对一的关系。

【问题讨论】:

  • 您的设计令人困惑 - Id 应该是 Table1 的主键还是 Table2 的外键?能否请教一下这两个表的 SQL 定义?
  • 您需要在填充的 Table2 中添加一个包含:context.Table1List.Include(t => t.Table2).FirstOrDefault( j => j.Id == 1)
  • 请检查我的回答。
  • @aguafrommars 完全正确。和我的回答一样。

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


【解决方案1】:

更新:

你必须改变你的模型:

public class Table1{
    public int Id{get; set;} //Primary key by convention
    [ForeignKey("Table2")]
    public int Table2Id{get; set;}
    public virtual Table2 Table2{get; set;}
}

public class Table2{
    public int Id{get; set;} //Primary key by convention
    public virtual Table1 Table1{get; set;}
}

在你的上下文中你必须设置这个:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // Configure table1 & table2 entity
    modelBuilder.Entity<Table2>()
                .HasOptional(s => s.Table1) // Mark Table1 property optional in Table2 entity
                .WithRequired(ad => ad.Table2); // mark Table1 property as required in Table2 entity. Cannot save Table1 without Table
}

当您想从一个表中获取数据时,还需要从相关表中获取数据,您可以在查询中使用Include 方法,例如:

var result  = var t1 = context.Table1List.Include(x=>x.Table2).FirstOrDefault( j => j.Id == 1);

使用此代码,您可以获得有关表的数据。

如果您愿意,我可以为您创建更多示例。

【讨论】:

  • 您是否只是从@spender 的答案中复制/粘贴了类定义?大笑
  • 不走运。我也有很多模型已经以这种方式设置。他们也不工作。但是,我相信您是在假设 EF 会自动填充这些内容。表 1 和表 2 也具有 1 对 1 的关系。所以 table1s 的列表不是一个真实的陈述。我相信我的模型显示了这一点。表 1 和表 2 也共享 ID。如果我要运行您的代码,它将找不到 Table2Id。
  • @Mike 您是否将您的属性设置为虚拟?
  • 我删除了最后一条评论...添加包含工作。这就是我所做的一切。然而,我的印象是我不必这样做。添加包含本质上与我编写另一个语句来获取表相同。我认为我没有尝试过 OnModelCreating 中的“WithRequired”设置。这看起来很积极。我也会试试看。但是,您的示例仍然是错误的。没有名为 Table2Id 的列。只需 Table1 和 2 共享相同的 Id。如果我要添加 Column("...") 属性,则会出现重复错误。我的示例没有显示虚拟,但我的代码显示。
  • @Mike 在我看来您的问题出在您的表格中,因为不正确,请查看此行entityframeworktutorial.net/code-first/… 以了解有关表格生成的信息。
【解决方案2】:

让接线主要遵循惯例并假设一对多的关系,您的意思是要制作一组看起来像这样的模型吗?

public class Table1
{
    public int Id { get; set; }     // Primary key by convention
    [ForeignKey("Table2")]
    public int Table2Id { get; set; }
    public Table2 Table2 { get; set; }
}

public class Table2
{
    public int Id { get; set; }     //Primary key by convention
    public ICollection<Table1> Table1s { get; set; }
}

【讨论】:

  • 查看对 AmirReza-Farahlagha 的评论
【解决方案3】:

你需要的是Lazy Loading

通过检查文档,您会发现必须显式启用延迟加载:

.AddDbContext<BloggingContext>(
    b => b.UseLazyLoadingProxies()
          .UseSqlServer(myConnectionString));

并且您的Table2 属性必须是virtual

public class Table1 
{  
    public virtual Table2 Table2{get;set;}
}

你甚至不需要Id 外键!

【讨论】:

  • 我会尝试延迟加载...我想我以前尝试过,但不记得为什么 id 不起作用。我举的例子和你的有点不同。会回复你的。如果您没有确切的属性格式或在 onModelBuilding 中设置它,您将需要外键属性。你最后的说法并不完全正确。
  • @Mike 当然,还要检查this documentation。而且,正如我所见,您同时使用了KeyForeignKey 属性,你应该为你的外键引入新的属性。
  • 没有 UseLazyLoadingProxies 的选项,是否对此有特别的参考?
  • 请注意:此功能是在 EF Core 2.1 中引入的。您拥有哪个版本的 EF Core?
  • 2.0 AmirReza... 只需将 Include 添加到上下文即可。在那一点上一切正常。
猜你喜欢
  • 2011-05-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多