【问题标题】:Entity Framework - Code First - Foreign Key Constraint实体框架 - 代码优先 - 外键约束
【发布时间】:2021-01-05 19:07:27
【问题描述】:

我正在使用带有实体框架的代码优先方法开发数据库。

我想在几个表之间使用外键,例如:

 public class Producer
    {

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

        [Required]
        [StringLength(254)]
        public string Name { get; set; }
    }

然后另一个文件模型被简化为

 public class Product
    {

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

        [Required]
        [StringLength(254)]
        public string Name { get; set; }
    }

我想要的是在 Product 上定义一个 ProducerId 字段并将其链接到 Producers ID 字段,但我不知道如何告诉它它链接到哪个模型/表。

谁能澄清一下?我认为根据我阅读的内容,我似乎需要使 ID 字段更具描述性,EF 会找到该字段,ProductId 是 Products Id 字段 - 但我仍然不肯定它会跨表工作。

这是正确的还是我错过了什么?

编辑:

我尝试了下面的第一个答案,但使用的表格不止两个,并且得到了这个错误:


fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
      Failed executing DbCommand (46ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      CREATE TABLE `Product` (
          `ProductId` int NOT NULL AUTO_INCREMENT,
          `ProducerId` int NOT NULL,
          `ProductCategoryId` int NOT NULL,
          `ProductStyleId` int NOT NULL,
          `Name` varchar(254) NULL,
          `Year` datetime NOT NULL,
          `CreatedAt` datetime NOT NULL,
          `CategoryId` int NOT NULL,
          `StyleId` int NOT NULL,
          `Image` varbinary(4000) NULL,
          `TastingNotes` text NULL,
          `Description` text NULL,
          PRIMARY KEY (`ProductId`),
          CONSTRAINT `FK_Product_Producers_ProducerId` FOREIGN KEY (`ProducerId`) REFERENCES `Producers` (`ProducerId`) ON DELETE CASCADE,
          CONSTRAINT `FK_Product_ProductCategory_ProductCategoryId` FOREIGN KEY (`ProductCategoryId`) REFERENCES `ProductCategory` (`ProductCategoryId`) ON DELETE CASCADE,
          CONSTRAINT `FK_Product_ProductStyle_ProductStyleId` FOREIGN KEY (`ProductStyleId`) REFERENCES `ProductStyle` (`ProductStyleId`) ON DELETE CASCADE
      );
Failed executing DbCommand (46ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
CREATE TABLE `Product` (
    `ProductId` int NOT NULL AUTO_INCREMENT,
    `ProducerId` int NOT NULL,
    `ProductCategoryId` int NOT NULL,
    `ProductStyleId` int NOT NULL,
    `Name` varchar(254) NULL,
    `Year` datetime NOT NULL,
    `CreatedAt` datetime NOT NULL,
    `CategoryId` int NOT NULL,
    `StyleId` int NOT NULL,
    `Image` varbinary(4000) NULL,
    `TastingNotes` text NULL,
    `Description` text NULL,
    PRIMARY KEY (`ProductId`),
    CONSTRAINT `FK_Product_Producers_ProducerId` FOREIGN KEY (`ProducerId`) REFERENCES `Producers` (`ProducerId`) ON DELETE CASCADE,
    CONSTRAINT `FK_Product_ProductCategory_ProductCategoryId` FOREIGN KEY (`ProductCategoryId`) REFERENCES `ProductCategory` (`ProductCategoryId`) ON DELETE CASCADE,
    CONSTRAINT `FK_Product_ProductStyle_ProductStyleId` FOREIGN KEY (`ProductStyleId`) REFERENCES `ProductStyle` (`ProductStyleId`) ON DELETE CASCADE
);
MySql.Data.MySqlClient.MySqlException (0x80004005): Cannot add foreign key constraint
   at MySql.Data.MySqlClient.MySqlStream.ReadPacket()
   at MySql.Data.MySqlClient.NativeDriver.GetResult(Int32& affectedRow, Int64& insertedId)
   at MySql.Data.MySqlClient.Driver.GetResult(Int32 statementId, Int32& affectedRows, Int64& insertedId)
   at MySql.Data.MySqlClient.Driver.NextResult(Int32 statementId, Boolean force)
   at MySql.Data.MySqlClient.MySqlDataReader.NextResult()
   at MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior)
   at MySql.Data.MySqlClient.MySqlCommand.ExecuteReader()
   at MySql.Data.MySqlClient.MySqlCommand.ExecuteNonQuery()
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteNonQuery(RelationalCommandParameterObject parameterObject)
   at Microsoft.EntityFrameworkCore.Migrations.MigrationCommand.ExecuteNonQuery(IRelationalConnection connection, IReadOnlyDictionary`2 parameterValues)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.MigrationCommandExecutor.ExecuteNonQuery(IEnumerable`1 migrationCommands, IRelationalConnection connection)
   at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.UpdateDatabase(String targetMigration, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabaseImpl(String targetMigration, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.UpdateDatabase.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
C

【问题讨论】:

  • Product 类上添加public int PRoductId {get;set;} 然后添加public virtual Product Product { get; set; }
  • [ForeignKey("PrdouctId")] 是可选属性
  • 我不认为我遵循你所说的......你能详细说明一下吗?你要我把id字段改成ProductId,然后加一个虚拟构造函数?我不明白你的第二条评论是什么意思
  • 希望我的回答很清楚
  • 另外我想说的是ProducerId 不是ProductId 所以我的错。

标签: c# asp.net entity-framework ef-code-first


【解决方案1】:

要添加foreign key,只需将其添加到Product 类添加:

public int ProducerId { get; set; }

[ForeignKey("ProducerId")]  //This attribute is optional bc EF should recognize Product obj specifi

public virtual Producer Producer { get; set; }

通过添加public virtual Producer Producer,EF Core 应该将ProducerId 属性识别为foreign keyvirtual 用于启用Lazy Loading,如果你愿意的话。

[ForeignKey()] 是一个可选属性,用于显式指向 foreignnavigation 键。这篇文章应该进一步解释[ForeignKey()] 的可选使用。 How Should I Declare Foreign Key Relationships Using Code First Entity Framework (4.1) in MVC3?

明确地说,要简单地添加一个foreign 键,只需将其添加到类中:

public int ProducerId { get; set; }
public virtual Producer Producer { get; set; }

【讨论】:

  • 我提供了一种方法。但是有很多方法可以表示外键和导航键。研究 Fluent Api 也是一个很好的方法。 docs.microsoft.com/en-us/ef/core/modeling/…
  • 我现在正在尝试这种方式...我尝试了 Janzens,我可能做错了什么,但我的数据库现在无法构建。
  • 有时,如果表中已有数据,您要向其中添加外键。由于限制,它不会构建。
  • 这并没有给我一个错误,但我现在有一个新问题,当我删除我的数据库并在以这种方式设置后重新开始时(使用你的最后一个示例)然后我进行迁移和更新,我只得到一张桌子。对于生产者,但不是其他人
  • 你的新课程是什么?你能把它加到帖子里吗?正在使用迁移吗?
【解决方案2】:

假设您的生产者与产品存在一对多关系,我会这样安排:

public class Producer
    {

        [Key]
        public int ProducerID { get; set; }

        [Required]
        [StringLength(254)]
        public string Name { get; set; }

        public ICollection<Product> Products { get; set; }
    }

public class Product
    {

        [Key]
        public int ProductID { get; set; }

        public int ProducerID { get; set; }

        [Required]
        [StringLength(254)]
        public string Name { get; set; }

        public Producer Producer { get; set;}
    }

EF 将在从那里迁移期间完成繁重的工作,您可以检查上下文模型快照以确保它在更新数据库之前看起来正确。如果您还没有,我建议您查看 Microsoft Docs 中的 EF 教程。

【讨论】:

  • ICollection 产品出现在数据库中的是什么?集合构成什么类型​​的字段?只需命名一个 PrducerId 然后给它一个字段给生产者将正确设置这些字段并链接这些字段?不需要加外键属性吗?
  • ICollection 代表一组对象——假设生产者将提供多个产品。如果这只是一对一的关系,那么您将有一个 Public Product Product 代替。 ProductsProducer 实际上被认为是 navigation properties 并且在 EF 构建所有内容时不会在 DB 中有列,但对于提供 EF 是必需的上下文并允许您访问相关数据。因为您在 **ProducerID** 中指定了类的名称(这将是您的外键),所以无需明确将其视为外键。
  • EF 眼见为实,因此我建议您在创建迁移后检查模型上下文快照,或者甚至运行更新并查看 SQL 中的对象进行确认。以下是关于导航属性的更详细说明:docs.microsoft.com/en-us/ef/ef6/fundamentals/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-05
  • 2012-05-10
  • 2015-02-24
  • 2011-08-05
  • 1970-01-01
相关资源
最近更新 更多