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 - 映射到现有数据库并指定外键名称