" ReferentialConstraint中的依赖属性映射到存储生成的列。"在持久计算列上(EntityFramework DB优先)

时间:2016-08-02 08:37:30

标签: c# asp.net entity-framework sql-server-2012 entity-framework-6

我已根据文章Implementing Table Inheritance in SQL Server在我的SQL-Server中实现了模拟表继承构造。

除了使用简单的1到0 ... 1关系这一事实之外,您还要为类型表创建另一个约束,该类型表列出了基表的所有可能子类型,如段落中的文章" Modeling One-约束约束"。

每个子表都包含一个TYPE字段,该字段具有ComputedColumnSpecification,其持久化数字表示类型表中类型的ID。由于TYPE字段是约束的一部分,因此它将确保只能为基础数据集创建一个子节点。

为了更好地理解,我创建了一个示例数据库,用于描述匹配的ASP.NET解决方案的问题。要在本地环境中复制问题,请创建一个名为" PLAYGROUND"在执行此脚本之前:

USE [PLAYGROUND]
GO
/****** Object:  Table [dbo].[USER] ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[USER](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [TYPE__ID] [int] NOT NULL,
    [Enabled] [bit] NOT NULL,
    [Username] [nvarchar](32) NOT NULL,
    [Password] [nchar](32) NOT NULL,
    [Email] [nvarchar](255) NOT NULL,
 CONSTRAINT [PK_USER] PRIMARY KEY CLUSTERED 
(
    [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
/****** Object:  Table [dbo].[NATURAL_USER] ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[NATURAL_USER](
    [ID] [int] NOT NULL,
    [TYPE]  AS ((1)) PERSISTED NOT NULL,
    [BirthDate] [date] NOT NULL,
 CONSTRAINT [PK_NATURAL_USER] PRIMARY KEY CLUSTERED 
(
    [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
SET ANSI_PADDING OFF
GO
/****** Object:  Table [dbo].[JURIDICAL_USER] ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [dbo].[JURIDICAL_USER](
    [ID] [int] NOT NULL,
    [TYPE]  AS ((2)) PERSISTED NOT NULL,
    [CompanyName] [nvarchar](256) NOT NULL,
    [RegistrationNo] [nvarchar](max) NOT NULL,
    [Description] [nvarchar](max) NOT NULL,
 CONSTRAINT [PK_LEGAL_USER] PRIMARY KEY CLUSTERED 
(
    [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] TEXTIMAGE_ON [PRIMARY]

GO
SET ANSI_PADDING OFF
GO
/****** Object:  Table [dbo].[USER_T] ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[USER_T](
    [ID] [int] IDENTITY(1,1) NOT NULL,
    [TYPE] [nvarchar](32) NOT NULL,
 CONSTRAINT [PK_USER_T] PRIMARY KEY CLUSTERED 
(
    [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
/****** Object:  Index [IX_USER] ******/
ALTER TABLE [dbo].[USER] ADD  CONSTRAINT [IX_USER] UNIQUE NONCLUSTERED 
(
    [Username] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
/****** Object:  Index [PK_USER_TYPE] ******/
CREATE UNIQUE NONCLUSTERED INDEX [PK_USER_TYPE] ON [dbo].[USER]
(
    [ID] ASC,
    [TYPE__ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
SET ANSI_PADDING ON

GO
/****** Object:  Index [IX_USER_T] ******/
ALTER TABLE [dbo].[USER_T] ADD  CONSTRAINT [IX_USER_T] UNIQUE NONCLUSTERED 
(
    [TYPE] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
GO
SET ANSI_PADDING ON

GO
/****** TYPE DATA ******/
SET IDENTITY_INSERT [dbo].[USER_T] ON 
GO
INSERT [dbo].[USER_T] ([ID], [TYPE]) VALUES (2, N'JURIDICAL_USER')
GO
INSERT [dbo].[USER_T] ([ID], [TYPE]) VALUES (1, N'NATURAL_USER')
GO
SET IDENTITY_INSERT [dbo].[USER_T] OFF
GO
/****** Contraints ******/
ALTER TABLE [dbo].[JURIDICAL_USER]  WITH CHECK ADD  CONSTRAINT [FK_JURIDICAL_USER___USER] FOREIGN KEY([ID])
REFERENCES [dbo].[USER] ([ID])
GO
ALTER TABLE [dbo].[JURIDICAL_USER] CHECK CONSTRAINT [FK_JURIDICAL_USER___USER]
GO
ALTER TABLE [dbo].[JURIDICAL_USER]  WITH CHECK ADD  CONSTRAINT [FK_JURIDICAL_USER___USER___TYPEVALIDATION] FOREIGN KEY([ID], [TYPE])
REFERENCES [dbo].[USER] ([ID], [TYPE__ID])
GO
ALTER TABLE [dbo].[JURIDICAL_USER] CHECK CONSTRAINT [FK_JURIDICAL_USER___USER___TYPEVALIDATION]
GO
ALTER TABLE [dbo].[NATURAL_USER]  WITH CHECK ADD  CONSTRAINT [FK_NATURAL_USER___USER] FOREIGN KEY([ID])
REFERENCES [dbo].[USER] ([ID])
GO
ALTER TABLE [dbo].[NATURAL_USER] CHECK CONSTRAINT [FK_NATURAL_USER___USER]
GO
ALTER TABLE [dbo].[NATURAL_USER]  WITH CHECK ADD  CONSTRAINT [FK_NATURAL_USER___USER___TYPEVALIDATION] FOREIGN KEY([TYPE])
REFERENCES [dbo].[USER_T] ([ID])
GO
ALTER TABLE [dbo].[NATURAL_USER] CHECK CONSTRAINT [FK_NATURAL_USER___USER___TYPEVALIDATION]
GO
ALTER TABLE [dbo].[USER]  WITH CHECK ADD  CONSTRAINT [FK_USER___USER_T] FOREIGN KEY([TYPE__ID])
REFERENCES [dbo].[USER_T] ([ID])
GO
ALTER TABLE [dbo].[USER] CHECK CONSTRAINT [FK_USER___USER_T]
GO
USE [master]
GO
ALTER DATABASE [PLAYGROUND] SET  READ_WRITE 
GO

USER是基表,表NATURAL_USERJURIDICAL_USER是其子项。 USER_TUSER的类型表。

现在,在使用EntityFramework 6的ASP.NET应用程序中,我尝试按以下方式创建新用户:

using (PLAYGROUNDEntities model = new PLAYGROUNDEntities())
{
    USER user = new USER();
    user.Username = "admin";
    user.Password = "RANDOMHASH#123456";
    user.Email = "admin@example.org";

    user.NATURAL_USER = new NATURAL_USER();
    user.NATURAL_USER.BirthDate = new DateTime(1980, 01, 01);

    model.USER.Add(user);
    model.SaveChanges();
}

model.SaveChanges();上我得到了例外:

  

ReferentialConstraint中的依赖属性映射到存储生成的列。栏目:' TYPE'。

示例解决方案:https://dl.dropboxusercontent.com/u/55589036/zzzOther/Playground.zip(示例代码位于Page_Load的{​​{1}}。

据我所知,EntityFramework尝试设置列字段并失败,因为它的存储生成(持久化)。当我设置Default.aspx.cs时甚至会发生这种情况。

我尝试覆盖user.NATURAL_USER.TYPE = 1;以附加我自己的规则并将OnModelCreating列定义为TYPE,但永远不会调用Computed,因为我 EDMX-之后,我想坚持这一点。

因此,这个实体模型是基于数据库生成的,我希望保持这种方式,而且每次我更新模型时都不想编辑任何代码。

另外,我认为表继承概念在数据库层上实现得很好,因为它不使用触发器。我想保持它无触发。

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:2)

我对EF一无所知,但我会将您的TYPE列创建为普通列,而不是计算,不会保留。

然后我将其默认值设置为所需的值并添加CHECK约束以确保无法更改。

设置外键的T-SQL脚本的其余部分保持不变。

例如,对于NATURAL_USER,它看起来像这样:

CREATE TABLE [dbo].[NATURAL_USER](
    [ID] [int] NOT NULL,
    [TYPE] [int] NOT NULL,
    [BirthDate] [date] NOT NULL,
CONSTRAINT [PK_NATURAL_USER] PRIMARY KEY CLUSTERED 
(
    [ID] ASC
))
GO

ALTER TABLE [dbo].[NATURAL_USER]  WITH CHECK 
ADD  CONSTRAINT [CK_NATURAL_USER] CHECK  (([TYPE]=(1)))
GO

ALTER TABLE [dbo].[NATURAL_USER] 
CHECK CONSTRAINT [CK_NATURAL_USER]
GO

ALTER TABLE [dbo].[NATURAL_USER] 
ADD  CONSTRAINT [DF_NATURAL_USER_TYPE]  DEFAULT ((1)) FOR [TYPE]
GO

答案 1 :(得分:2)

在实施该方法时我犯了一个可怕的错误,但它之前有效。我意外地搞砸了约束FK_NATURAL_USER___USER___TYPEVALIDATION

它应该像FK_JURIDICAL_USER___USER___TYPEVALIDATION约束一样构建。

EF能够处理持久列。问题是它试图写入[USER_T]的PK,它根本不应该是约束的一部分。

对所有浪费时间的人抱歉。