我应该在 EF 中创建简单的一对一关系。但是当我尝试插入时收到以下错误:
ReferentialConstraint is mapped to a store-generated column. Column: 'ACCOUNT_ID'.
控制台应用示例:
namespace EF_ConsoleApp_Test
{
public class Program
{
public static void Main(string[] args)
{
var account = new Account
{
AccountNumber = "00123456",
CustomerValue = new Customer { FirstName = "Joe" }
};
using (var db = new MainContext())
{
db.Accounts.Add(account);
db.SaveChanges();
}
}
}
[Serializable]
[Table("CUSTOMERS")]
public class Customer
{
[Key]
[Column("CUSTOMER_ID")]
public int? Id { get; set; }
[Required]
[Column("FIRST_NAME")]
[StringLength(45)]
public string FirstName { get; set; }
public virtual Account Account { get; set; }
public Customer() { }
}
[Serializable]
[Table("ACCOUNTS")]
public class Account
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
[Column("ACCOUNT_ID")]
public int? Id { get; set; }
[Required]
[Column("ACCOUNT_NUMBER")]
[Display(Name = "Account Number")]
[StringLength(16)]
public string AccountNumber { get; set; }
[Column("CUSTOMER_ID")]
public int? CustomerId { get; set; }
public virtual Customer CustomerValue { get; set; }
/// <summary>
/// Default Constructor
/// </summary>
public Account() { }
}
internal class MainContext : DbContext
{
internal MainContext() : base("name=DB.Context")
{
Database.SetInitializer<MainContext>(null);
}
public virtual DbSet<Account> Accounts { get; set; }
public virtual DbSet<Customer> Customers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Configure FK
modelBuilder.Entity<Customer>()
.HasRequired(c => c.Account)
.WithRequiredPrincipal(a => a.CustomerValue);
base.OnModelCreating(modelBuilder);
}
}
}
数据库表创建语句:
CREATE TABLE [dbo].[CUSTOMERS](
[CUSTOMER_ID] [INT] IDENTITY(1,1) NOT NULL,
[FIRST_NAME] [varchar](45) NOT NULL,
CONSTRAINT [PK_CUSTOMERS] PRIMARY KEY CLUSTERED
(
[CUSTOMER_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
CREATE TABLE [dbo].[ACCOUNTS](
[ACCOUNT_ID] [INT] IDENTITY(1,1) NOT NULL,
[CUSTOMER_ID] [int] NOT NULL,
[ACCOUNT_NUMBER] [varchar](16) NOT NULL,
CONSTRAINT [PK_ACCOUNTS] PRIMARY KEY CLUSTERED
(
[ACCOUNT_ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
ALTER TABLE [dbo].[ACCOUNTS] WITH CHECK ADD CONSTRAINT [FK_ACCOUNTS_CUSTOMERS] FOREIGN KEY([CUSTOMER_ID])
REFERENCES [dbo].[CUSTOMERS] ([CUSTOMER_ID])
GO
App.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
</configSections>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.1" />
</startup>
<connectionStrings>
<add name="DB.Context"
connectionString="data source=localdb;initial catalog=EF_TEST;Integrated Security=SSPI;MultipleActiveResultSets=True;App=EntityFramework;Connection Timeout=30;encrypt=true;trustServerCertificate=true;"
providerName="System.Data.SqlClient" />
</connectionStrings>
<entityFramework>
<defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">
<parameters>
<parameter value="mssqllocaldb" />
</parameters>
</defaultConnectionFactory>
<providers>
<provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
</providers>
</entityFramework>
</configuration>
我需要更改什么才能使这项工作正常进行?
注意事项:
- 我使用的是 EF 6.2 和 .NET 4.7.1。
- 我继承了这个数据库架构,一对一的关系无法更改。
- 我试图通过只调用一次 SaveChanges() 来避免显式创建事务,而不是包装一个单独的调用以先创建客户,然后再创建帐户。
最佳答案
按照惯例,EF6 使用所谓的 Shared Primary Key Association 表示一对一关系,其中依赖实体的 PK 也用作主体实体的 FK。
在您的情况下,它认为 Account.Id
是 Customer
的 FK,并且由于它是自动生成的,所以您会遇到有问题的异常。
另一个问题是 EF6 不支持具有显式 FK 属性的一对一关系(没有类似于一对多关系的 HasForeignKey
流畅 API)。
因此您需要从模型中删除 AccountId
属性,只保留导航属性。此外,虽然不是非常必要,但最好遵循命名约定,将其称为 Account
而不是 AccountValue
。
换句话说,替换
[Column("CUSTOMER_ID")]
public int? CustomerId { get; set; }
public virtual Customer CustomerValue { get; set; }
与
public virtual Customer Customer { get; set; }
可以使用 MapKey
流畅的 API 指定 FK 列名:
modelBuilder.Entity<Customer>()
.HasRequired(c => c.Account)
.WithRequiredPrincipal(a => a.Customer)
.Map(m => m.MapKey("CUSTOMER_ID")); // <--
大功告成。
现在下面的代码首先正确地插入了一个新的 Customer
,然后是一个引用它的新的 Account
:
var account = new Account
{
AccountNumber = "00123456",
Customer = new Customer { FirstName = "Joe" }
};
db.Accounts.Add(account);
db.SaveChanges();
关于c# - Entity Framework - 一对一 - ReferentialConstraint 映射到存储生成的列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50011305/