我们如何在 ASP.NET Core & EF Core & C# 上将多个外键从一个模型添加到另一个模型

How can we add multiple foreign keys from one model to another on ASP.NET Core & EF Core & C#

假设我有一个 ApplicationUser : IdentityUser 模型 class,它具有身份关系,默认情况下它有一个字符串 ID,并且在用户注册时分配了角色。

ApplicationUsers 将有不同的角色,例如学生和图书馆。

图书馆会有图书清单,而学生会有订单清单。

现在我想创建一个名为 Orders 的另一个模型的列表,但是 Orders 模型 class 将有两个 UserId 作为来自 [=17] 的外键=].

ApplicationUser: IdentityUser 
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public List<Libraries> Libraries { get; set; }
    public List<Orders> Orders { get; set; }
}

由于 ApplicationUserASPNetRoles 相连,我想在 Orders 模型 class 上实现的是我想要不同的 StudentId LibraryId 来自同一个 table 即 ApplicationUser:

public class Orders 
{ 
    [Key]
    public id OrderId {get; set;}

    [ForeignKey("StudentId")]
    public string StudentId { get; set; }
    public ApplicationUser Student {get; set;}
 
    [ForeignKey("LibraryId")]
    public string LibraryId {get; set;} 
    public ApplicationUser Library {get; set;}
}

有什么办法可以做到这一点吗?这种情况的最佳解决方案是什么?我确实尝试 ICollection 并列出但仍然相同。任何关于此的建议都会很棒。

当我 运行 Add-Migrations 时,我得到这个错误:

System.InvalidOperationException: Unable to determine the relationship represented by navigation 'ApplicationUser.OrdersLists' of type 'ICollection'. Either manually configure the relationship, or ignore this property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

谢谢。

好的,你的模型看起来不太对...

在您的用户 class 中,您有一个订单集合和一个名为图书馆的 class 集合。然而,在您的订单 class 中,您有一个名为 Library 的 属性,但指向 ApplicationUser class?

EF 确实支持对同一个 class 进行多次引用,但您需要明确告诉它 FK 名称是什么。 EF 的默认约定是将 FK 名称基于导航 属性 的 类型 ,而不是导航 属性.

的名称

取以下内容:

public class Order
{
    ....

    public int CreatedById { get; set; }
    public virtual ApplicationUser CreatedBy { get; set; }

    public int LastModifiedById { get; set; }
    public virtual ApplicationUser LastModifiedBy { get; set; }
}

默认情况下,EF 希望使用“ApplicationUser_Id”或“ApplicationUserId”作为两个导航属性的 FK 名称,选择“ApplicationUser_Id”和“ApplicationUser_Id1" 如果留给它自己的设备与模式。在这种情况下,我们需要将其配置为使用我们所需的 FK 属性:

[ForeignKey("CreatedBy")]
public int CreatedById { get; set; }
public virtual ApplicationUser CreatedBy { get; set; }

[ForeignKey("LastModifiedBy")]
public int LastModifiedById { get; set; }
public virtual ApplicationUser LastModifiedBy { get; set; }

或者FK属性可以放在导航上属性:

public int CreatedById { get; set; }
[ForeignKey("CreatedById")]
public virtual ApplicationUser CreatedBy { get; set; }

public int LastModifiedById { get; set; }
[ForeignKey("LastModifiedById")]
public virtual ApplicationUser LastModifiedBy { get; set; }

ForeignKey 属性有点奇怪,因为它表示“我是...的 FK”(如果在 FK 属性 上,或者它表示“我的 FK 是 .. .." 如果在导航上 属性.

对于 EF Core,FK 属性 可以被 EF 忽略并被 EF 视为阴影 属性,建议避免实体中有两个真实来源。

[ForeignKey("CreatedById")]
public virtual ApplicationUser CreatedBy { get; set; }

[ForeignKey("LastModifiedById")]
public virtual ApplicationUser LastModifiedBy { get; set; }

如果您希望在关系的另一端引用 bi-directional,您可能需要将它们映射出来。例如,如果我想在我的 ApplicationUser class:

中使用“CreatedOrders”
public class ApplicationUser
{
    // ...

    public virtual ICollection<Order> CreatedOrders { get; set; } = new List<Order>();
}

现在通常最好告诉 EF 将其关联到什么,因为 Order 有两个对应用程序用户的引用。同样,这可以在关系的任何一方完成。所以在返回我们订单的情况下 class:

[ForeignKey("CreatedById"), InverseProperty("CreatedOrders")]
public virtual ApplicationUser CreatedBy { get; set; }

这告诉 EF 此记录上的 CreatedBy 是访问 CreatedOrders 的订单时要使用的 link。

回到你的例子,有点令人困惑为什么 ApplicationUser 会包含一个库的集合,而一个订单期望一个“库”是一个用户。