9

我已經在我的SQL Server中基於文章Implementing Table Inheritance in SQL Server實現了一個模擬表繼承構造。」ReferentialConstraint中的依賴屬性映射到商店生成的列。「在一個持久的計算列(EntityFramework數據庫優先)

除了事實用簡單的1到0 ... 1間的關係,創建另一個約束,列出了所有可能的子類型,在段落在文章中解釋了基表的類型表「造型一對一約束條件「。

你的子表的每一個包含有一個堅持數字,表示在類型表類型的ID的ComputedColumnSpecification類型字段。由於TYPE字段是約束的一部分,它將確保只有一個孩子可以創建到基礎數據集。

爲了更好地理解我已經創建了用於與匹配的ASP.NET解決方案來描述問題的樣本數據庫。要複製在當地的環境問題,在執行此腳本之前創建一個名爲「樂園」數據庫:

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 = "[email protected]"; 

    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(示例代碼是在Default.aspx.csPage_Load

我明白了,的EntityFramework試圖設置列字段和失敗,因爲它的商店產生的(持續)這甚至發生在我設置user.NATURAL_USER.TYPE = 1;

我試圖重寫OnModelCreating附上我自己的規則和定義都TYPE列作爲Computed,但OnModelCreating不會被調用,因爲我做EDMX在之後,我想堅持這一點。

因此,基於數據庫生成此實體模型,我想保持下去,再加上我不想編輯,當我再次更新我的模型每一次的任何代碼。

而且,我認爲表繼承的概念在數據庫層上很好實現的,因爲它不使用觸發器。我想保持它不觸發。

我該如何解決這個問題?

+0

爲什麼不直接使用帶有自己的繼承(TPT或TPH)的EF?你有使用DB First的項目限制嗎? – bubi

+0

@bubi TPT或TPH方法只是EF上的繼承系統,仍然允許使用普通SQL在數據庫上繞過它。 TPT/TPH要求我在重新創建EDMX文件後在設計器中創建關聯。如果我在這裏錯了,請糾正我。 – modiX

+0

TPT和TPH是與Code First嚴格相關的方法。如果您正在處理現有的數據庫(DB First + EDMX)不是一個好方法。你的情況是TPH(單表+鑑別字段),但如果DB + EDMX是一個約束標準EF TPH不是一個好方法。 – bubi

回答

2

實施辦法時,我已經做了可怕的錯誤,但它工作過。我不小心弄亂了約束條件FK_NATURAL_USER___USER___TYPEVALIDATION

它應該像FK_JURIDICAL_USER___USER___TYPEVALIDATION約束。

EF能夠處理持久列。問題在於它試圖寫入[USER_T]的PK,這根本不應該是約束的一部分。

對於所有浪費時間的人,我都很抱歉。

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 
相關問題