繁体   English   中英

实体框架数据库表关联

[英]Entity Framework database tables association

我有一个这样的域模型:

public class Rental
{
    public int Id { get; set; }

    public DateTime DateRented { get; set; }
    public DateTime? DateReturned { get; set; }

    [Required]
    public Customer Customer { get; set; }

    [Required]
    public Movie Movie { get; set; }
}

实体框架将其与其他两个表( CustomersMovies )相关联,并在Rentals表中自动创建外键列。 在我的 .NET 课程中,我被教导通过添加Id属性与其他表建立关联,例如, Rental域模型将包含以下属性:

public int MovieId { get; set; }
public int CustomerId { get; set; }

但是代码在没有这些代码行的情况下运行良好。 你能向我解释一下哪种方法更好吗? 或者其中之一提供了更大的灵活性? 我是 .NET 的新手,所以每一个解释都会受到欢迎。

下面的第一行会抛出一个语法错误,这不是有效的 c# 代码

public MovieId { get; set; }
public CustomerId { get; set; }

第二件事 EF 足够聪明,可以知道实体之间的关系,并且从您的用例来看,当您想访问有关客户的信息(例如姓名)时,最好以这种方式放置 Typed 属性,您确实可以使用它使用rental.Customer.Name ,你不必单独拉它。

在 EF 定义架构的情况下使用 Code-First 时,EF 将使用约定在表中创建合适的 FK 列并在幕后使用这些列。 您可以使用您想要的任何命名约定定义您自己的 FK,但您需要告诉 EF 使用哪个列作为哪个表的 FK 关系。 这是通过使用[ForeignKey]属性或使用外键配置关系(modelBuilder 或EntityTypeConfiguration )来完成的。

按照约定,EF 将通过相关对象的类型定义 FK 列名称,这可能不是您想要的架构。 例如,如果您有一个 Order 实体,您希望引用 CreatedBy 和 LastModifiedBy 的 User 实体,您可能希望有类似的东西

public class Order
{
    // ...
    public virtual User CreatedBy { get; set; }
    public virtual User LastModifiedBy { get; set; }
}

EF 会像这样创建 FK:User_Id 和 User_Id2

这可能会绊倒想要在实体中包含 FK 的人:

public class Order
{
    // ...
    public int CreatedByUserId { get; set; }
    public virtual User CreatedBy { get; set; }
    public int LastModifiedByUserId { get; set; }
    public virtual User LastModifiedBy { get; set; }
}

... 期待它的工作然后想知道为什么表中的 ID 没有被填充。

要使用更有意义的 FK,您需要配置它们:

public class Order
{
    // ...
    [ForeignKey("CreatedBy")]
    public int CreatedByUserId { get; set; }
    public virtual User CreatedBy { get; set; }
    [ForeignKey("LastModifiedBy")]
    public int LastModifiedByUserId { get; set; }
    public virtual User LastModifiedBy { get; set; }
}

ForeignKey属性可以放在指向导航属性的 FK 上,也可以放在指向 FK 的导航属性上。

但是,我通常建议不要在实体中定义 FK,因为这可能会在更新引用时导致潜在问题,因为关系有 2 个真实来源。

我使用order.LastModifiedByUserId还是order.LastModifiedBy.UserId 如果我想更新用户并且某些代码引用了其中的一个怎么办? 如果我更改用户导航属性,订单上的 FK 何时更新? 如果我设置 FK 而不是导航属性怎么办?

如果我想更新订单的LastModifiedBy

我可能会想这样做:

var order = context.Orders.Single(x => x.OrderId == orderId);
order.LastModifiedByUserId = currentUserId;

但是,我应该这样做:

var currentUser = context.Users.Single(x => x.UserId == currentUserId);
var order = context.Orders.Single(x => x.OrderId == orderId);
order.LastModifiedBy = currentUser;

根据 LastModifiedBy 导航属性是预先加载还是 DBContext 可以填充它(因为它已经加载并且可以在使订单实体饱和时填充)将决定尝试更新 FK 的行为。 第二个选项是一致的,但是请注意,即使在那里,在调用SaveChanges之前,Order 上的任何 FK 都不会自动更新。

一般来说,完全避免在实体中暴露 FK 是一个更好的主意。 对于Map.MapKey ,这可以通过使用Map.MapKey来完成,其中 EF Core 支持阴影属性。 例如,配置以下实体以定义要使用的 FK 列名称,但避免暴露 FK 属性:

public class Order
{
    // ...
    public virtual User CreatedBy { get; set; }
    public virtual User LastModifiedBy { get; set; }
}

使用模型构建器或EntityTypeConfiguration

EF6

.HasRequired(x => x.CreatedBy)
    .WithMany()
    .Map(x => x.MapKey("CreatedByUserId"));
.HasRequired(x => x.LastModifiedBy)
    .WithMany()
    .Map(x => x.MapKey("LastModifiedByUserId"));

英孚核心

.HasOne(x => x.CreatedBy)
    .WithMany()
    .HasForeignKey("CreatedByUserId");
.HasOne(x => x.LastModifiedBy)
    .WithMany()
    .HasForeignKey("LastModifiedByUserId");

/w EF Core HasForeignKey可用于定义 FK 列的影子属性,而不是指向实体中的公开属性。 这里的优点是相关实体的密钥不再有两个真实来源。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM