EF 6 是不是要求外键具有反映外表名称的名称?

Posted

技术标签:

【中文标题】EF 6 是不是要求外键具有反映外表名称的名称?【英文标题】:Does EF 6 require a foreign key to have a name that reflects the name of the foreign table?EF 6 是否要求外键具有反映外表名称的名称? 【发布时间】:2021-06-17 08:21:49 【问题描述】:

我们正在使用 EF 6 的 Code First 和现有数据库。我们正在使用 SQL Server 我的老板使用从 TOAD 生成的 SQL 脚本创建表。通常按照这种模式创建表:

表名:例如:Person 主键:ID(ALWAYS只是ID)

通常在创建与另一个表具有 1 对 1 或 1 或 0 关系的表时,它是使用以下模式创建的:

表名:地址 主键:ID Person 的外键:PersonID

但是,我的老板用两张桌子打破了他的模式,这让我很伤心。我认为这是因为他将外键命名为不符合模式的东西,他在其他任何地方都使用过。但我可能是错的。当然,在我看来,EF 的代码首先与现有数据库并没有识别这种关系。这是导致问题的两个表的 SQL 的 sn-p(我正在删除不相关的列):

CREATE TABLE [app].[PersonnelCertification]
(
 [ID] Bigint IDENTITY NOT NULL,
 [CertificationTypeID] Bigint NOT NULL,
 [InstrumentModelID] Bigint NOT NULL,
 [PersonID] Bigint NOT NULL,
 [AgencyID] Bigint NOT NULL,
 [CertificationLevelID] Bigint NOT NULL,
)

这里是到 Proficiency 表的 SQL sn-p:

CREATE TABLE [app].[Proficiency]
(
 [ID] Bigint IDENTITY(1,1) NOT NULL,
 [PersonCertID] Bigint NOT NULL,
 [InstrumentID] Bigint NULL,
 [SolutionID] Bigint NOT NULL,
)

ALTER TABLE [app].[Proficiency] ADD CONSTRAINT [PersonnelCertification-Proficiency] FOREIGN KEY ([PersonCertID]) REFERENCES [app].[PersonnelCertification] ([ID]) ON UPDATE NO ACTION ON DELETE NO ACTION
go

ALTER TABLE [app].[Proficiency] ADD CONSTRAINT [Solution-Proficiency] FOREIGN KEY ([SolutionID]) REFERENCES [app].[Solution] ([ID]) ON UPDATE NO ACTION ON DELETE NO ACTION
go

ALTER TABLE [app].[Proficiency] ADD CONSTRAINT [Instrument-Proficiency] FOREIGN KEY ([InstrumentID]) REFERENCES [app].[Instrument] ([ID]) ON UPDATE NO ACTION ON DELETE NO ACTION
go

下面是 code first 使用现有数据库生成的结果代码,用于 Proficiency 表:

[Table("app.Proficiency")]
public partial class Proficiency

    public long ID  get; set; 

    public long PersonCertID  get; set; 

    public long? InstrumentID  get; set; 

    public long SolutionID  get; set; 

    public virtual Instrument Instrument  get; set; 

    public virtual Solution Solution  get; set; 

有一个名为 Solution 的表与 Proficiency 相关。有一个名为 Instrument 的表与 Proficiency 相关。生成的 Proficiency 模型类中没有任何与 PersonnelCertification 相关的内容。就像我说的那样,没有名为 PersonCert 的表。

我不知道如何解决这个问题。我尝试将[ForeignKey] 属性添加到PersonCertID,但这不起作用。我还尝试在 DbContext 生成的类中添加一些代码,用于定义两个表之间的关系,首先使用现有数据库编写代码无法识别,但我不知道什么会起作用。我希望知道 EF 6 是否使用诸如约定优于配置之类的东西来确定外键关系。例如,将 PersonCertID 重命名为 PersonnelCertificationID 会更好吗?或者有没有办法在 DbContext 中指定 Fuild API 来声明 Proficiency 和 PersonnelCertification 之间的关系?

【问题讨论】:

数据库端外键的名称与 EF 如何关联实体无关 为什么不让你的老板遵循其他地方使用的模式,这样你就可以复制粘贴调整你在其他地方使用的 EF 代码模式?或者最好还是让老板退出软件开发并专注于他们的角色(产品负责人、业务开发等 - 他们提供他们需要的功能规范,并将实施留给工程师) 您使用的是 Code First 还是 EF 设计器? 当命名约定不适合您时,您需要用很多话来说明您不知道如何在 EF 中映射关系。这一切都有据可查,例如docs.microsoft.com/en-us/ef/ef6/modeling/code-first/fluent/…。 你能用一整套重现问题的 DDL 更新问题吗? AFAIK 这应该可以正常工作。但正如@GertArnold 指出的那样,您始终可以只编写类并将它们手动映射到表。 【参考方案1】:

希望在某个地方你会有一个class PersonnelCertification,这样你就可以改变你的熟练程度,比如:

Table("app.Proficiency")]
public partial class Proficiency

    public long ID  get; set; 

    [ForeignKey(nameof(PersonnelCertification))]
    public long PersonCertID  get; set; 
    public virtual PersonnelCertification PersonnelCertification  get; set; 

    public long? InstrumentID  get; set; 

或者你可以改变它:

public partial class Proficiency

    public long ID  get; set; 

    
    public long PersonCertID  get; set; 
    [ForeignKey(nameof(PersonCertID))]
    public virtual PersonnelCertification PersonnelCertification  get; set; 

    public long? InstrumentID  get; set; 

或者您可以更改 PersonnelCertification:

class PersonnelCertification

    ...
    
    [ForeignKey(nameof(Proficiency.PersonCertID))]
    public ICollection<Proficiency> Proficiencies

使用最能吸引您将这些东西联系在一起的感觉。我喜欢选项2

注意,nameof 被编译器转为字符串;它需要一个 C#“事物”(类、方法、属性等)或“事物的路径”,并给出事物的字符串名称。它很有用,因为它意味着智能感知可以帮助您编写东西,并且如果您曾经通过内置的重构工具重命名,那么它将更新字符串不会出现的位置

【讨论】:

以上是关于EF 6 是不是要求外键具有反映外表名称的名称?的主要内容,如果未能解决你的问题,请参考以下文章

EF 4.1 RC Code First - 映射到现有数据库并指定外键名称

EF 6不同的DbSet名称来自它所持有的类

PLA 1.2 根据要求,与您的应用关联的卖家和公司名称未在应用或其元数据中反映名称“Lumique”

EF5.X Code First表关联与延迟加载

EF之Code First设置主外键关系

EF Core 6:查找中间表的名称