我正在使用EF 6.2.0
,EF Code-First
,.NET 4.7
,Azure SQL Database
。
我有一个EF Code-First模型,我需要在其上强制执行约束,以便新行不允许与其他ValidFromUtc
和{{的范围重叠1}} ValidToUtc
列。我希望约束在数据库中强制执行并由EF维护。
在我的EF模型中,我有以下属性和DateTime
:
DataAnnotations
如果[Required, Key]
public Guid Id { get; set; }
[Required, Index("UniqueIndexName", IsUnique = true, Order = 1)]
public Guid OwnerAccountId { get; set; }
[Required, Index("UniqueIndexName", IsUnique = true, Order = 2)]
public Guid PartnerAccountId { get; set; }
// I need a range constraint between ValidFromUtc and ValidToUtc to be enforced somehow.
[Required, Index("UniqueIndexName", IsUnique = true, Order = 3)]
public DateTime ValidFromUtc { get; set; }
[Required, Index("UniqueIndexName", IsUnique = true, Order = 4)]
public DateTime ValidToUtc { get; set; }
// Etc. etc.
或OwnerAccountId
的值无法插入或更新,则我需要的是强制执行给定PartnerAccountId
,ValidFromUtc
的行的方法与任何现有行重叠。
是否可以使用(按优先顺序)实现上述约束:
如果是这样,怎么办呢?哪种方法更好,为什么?
我现在能想到的唯一解决方案是创建一个插入/更新触发器。
任何指针都非常感谢!谢谢!
答案 0 :(得分:1)
不幸的是,我认为Trigger是唯一的选择:
CREATE TABLE [dbo].[UniqueDates](
[OwnerAccountId] [int] NOT NULL,
[ParentAccountId] [int] NOT NULL,
[ValidFromUtc] [datetimeoffset](7) NOT NULL,
[ValidToUtc] [datetimeoffset](7) NOT NULL,
CONSTRAINT [PK_UniqueDates] PRIMARY KEY CLUSTERED
(
[OwnerAccountId] ASC,
[ParentAccountId] 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
INSERT [dbo].[UniqueDates] ([OwnerAccountId], [ParentAccountId], [ValidFromUtc], [ValidToUtc]) VALUES (1, 1, CAST(N'2018-01-01T00:00:00.0000000+00:00' AS DateTimeOffset), CAST(N'2018-01-03T00:00:00.0000000+00:00' AS DateTimeOffset))
GO
INSERT [dbo].[UniqueDates] ([OwnerAccountId], [ParentAccountId], [ValidFromUtc], [ValidToUtc]) VALUES (1, 2, CAST(N'2018-01-04T00:00:00.0000000+00:00' AS DateTimeOffset), CAST(N'2018-01-05T00:00:00.0000000+00:00' AS DateTimeOffset))
GO
INSERT [dbo].[UniqueDates] ([OwnerAccountId], [ParentAccountId], [ValidFromUtc], [ValidToUtc]) VALUES (2, 1, CAST(N'2018-01-06T00:00:00.0000000+00:00' AS DateTimeOffset), CAST(N'2018-01-08T00:00:00.0000000+00:00' AS DateTimeOffset))
GO
create trigger [trg_i_Test] on [UniqueDates]
INSTEAD OF INSERT
AS
BEGIN
if exists (SELECT null
FROM [TEST].[dbo].[UniqueDates] [from]
Inner join [TEST].[dbo].[UniqueDates] [to] on ([from].ValidFromUtc between [to].ValidFromUtc and [to].ValidtoUtc)
and ([from].OwnerAccountId<>[to].OwnerAccountID or [from].ParentAccountId<>[to].ParentAccountID)
)
BEGIN
RAISERROR ('These dates break the rules.' ,16,1)
ROLLBACK TRANSACTION
END
ELSE
BEGIN
INSERT INTO [UniqueDates]
SELECT *
FROM inserted
END
END
GO
INSERT [dbo].[UniqueDates] ([OwnerAccountId], [ParentAccountId], [ValidFromUtc], [ValidToUtc]) VALUES (2, 4, CAST(N'2018-01-07T00:00:00.0000000+00:00' AS DateTimeOffset), CAST(N'2018-01-09T00:00:00.0000000+00:00' AS DateTimeOffset))
GO
答案 1 :(得分:0)
如果您希望所有来自EF,那么您必须使用EF Migrations。 (注意:我根本不是移民的粉丝)。这允许EF完全控制db(创建和迁移等),这也意味着你需要在C#代码中执行许多特定于数据库的东西(必填字段,字段类型等)。然后在种子例程中你会写一些代码,如:
context.Database.ExecuteSQLCommand("CREATE CONSTRAINT /* etc etc */");
(如果这只是两个原始的,您可以创建自己的属性以放置在EF模型上,然后使用反射来动态创建自定义约束。)