我有一个小模特:
Public Class Thing
Public Property Id As Integer
Public Property Name As String
End Class
匹配DbContext
:
Public Class Context
Inherits DbContext
Public Sub New()
MyBase.New("EfCodeFirstUniqueConstraintTest")
End Sub
Public Property Things As IDbSet(Of Thing)
Protected Overrides Sub OnModelCreating(modelBuilder As DbModelBuilder)
MyBase.OnModelCreating(modelBuilder)
BuildConstraints(modelBuilder)
End Sub
Private Sub BuildConstraints(modelBuilder As DbModelBuilder)
modelBuilder.Entity(Of Thing).Property(Function(m) m.Name) _
.HasMaxLength(255) _
.HasColumnAnnotation(IndexAnnotation.AnnotationName, _
New IndexAnnotation(New IndexAttribute("UniqueOrgUnitName") _
With {.IsUnique = True}))
End Sub
End Class
当我使用此代码将其放入使用EF6.1的解决方案时:
Sub Main()
Using db As New Context
Dim t = New Thing With {.Name = "Thingy"}
db.Things.Add(t)
db.SaveChanges()
End Using
End Sub
一切都按预期工作。 2. run会因为存在唯一的索引违规而抛出异常。
不幸的是,我需要我的应用程序不要丢弃整个数据库。所以我写了一个表和约束DbInitializer
,如下所示:
Public Class DbIniter
Implements IDatabaseInitializer(Of Context)
Public Sub InitializeDatabase(context As Context) Implements IDatabaseInitializer(Of Context).InitializeDatabase
DropAllTables(context)
Dim dbCreationScript = CType(context, IObjectContextAdapter).ObjectContext.CreateDatabaseScript()
context.Database.ExecuteSqlCommand(dbCreationScript)
CreateMetaDataTable(context)
Seed(context)
context.SaveChanges()
End Sub
Protected Sub DropAllTables(context As Context)
context.Database.ExecuteSqlCommand("EXEC sp_MSforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT all'")
Dim remainingTrys = 100
Dim everythingOk = False
While Not everythingOk AndAlso remainingTrys > 0
Try
context.Database.ExecuteSqlCommand("EXEC sp_MSforeachtable ""DECLARE @name nvarchar(max); SET @name = parsename('?', 1); EXEC sp_MSdropconstraints @name""")
context.Database.ExecuteSqlCommand("EXEC sp_MSforeachtable 'DROP TABLE ?'")
everythingOk = True
Catch ex As Exception
remainingTrys = remainingTrys - 1
End Try
End While
If Not everythingOk Then Throw New System.Data.Entity.Infrastructure.RetryLimitExceededException(String.Format("Database was not empty after last attempt."))
End Sub
Protected Sub CreateMetaDataTable(context As Context)
Dim sql = "CREATE TABLE dbo.__MigrationHistory ( MigrationId NVARCHAR(255) NOT NULL, CreatedOn DATETIME NOT NULL, Model VARBINARY(MAX) NOT NULL, ProductVersion NVARCHAR(32) NOT NULL);" _
& " ALTER TABLE dbo.__MigrationHistory ADD PRIMARY KEY (MigrationId); INSERT INTO dbo.__MigrationHistory (MigrationId, CreatedOn, Model, ProductVersion) VALUES ('InitialCreate', GetDate(), @p0, @p1);"
context.Database.ExecuteSqlCommand(sql, GetModel(context), GetProductVersion())
End Sub
Protected Function GetModel(context As Context) As Byte()
Using memoryStream As New MemoryStream
Using gzipStream As New GZipStream(memoryStream, CompressionMode.Compress)
Using writer = XmlWriter.Create(gzipStream, New XmlWriterSettings With {.Indent = True})
EdmxWriter.WriteEdmx(context, writer)
End Using
End Using
Return memoryStream.ToArray
End Using
End Function
Protected Overridable Sub Seed(context As Context)
End Sub
Protected Function GetProductVersion() As String
Return GetType(DbContext).Assembly.GetCustomAttributes(False).OfType(Of Reflection.AssemblyInformationalVersionAttribute).Single.InformationalVersion
End Function
End Class
使用此初始化程序,我的索引永远不会访问数据库。其他一切都很好。
ObjectContext.CreateDatabaseScript()
不会为索引返回任何SQL:
create table [dbo].[Things] (
[Id] [int] not null identity,
[Name] [nvarchar](255) null,
primary key ([Id])
);
使用默认的DbInitializer
,发送给DB的SQL如下所示:
CREATE TABLE [dbo].[Things] (
[Id] [int] NOT NULL IDENTITY,
[Name] [nvarchar](255),
CONSTRAINT [PK_dbo.Things] PRIMARY KEY ([Id])
)
然后是另一个这样的声明:
CREATE UNIQUE INDEX [UniqueOrgUnitName] ON [dbo].[Things]([Name])
有人知道为什么这不起作用吗?
当{_ 1}}返回时,index-SQL不包含在哪里?
答案 0 :(得分:0)
我不确切知道EF的历史但写了一个EF提供程序(https://jetentityframeworkprovider.codeplex.com/)我发现一些旧的EF版本用于使用DbProviderServices
接口生成对象项。该接口(您与初始化程序一起使用的接口)适用于StoreItemCollection
,我非常确定它不包含有关索引的信息,但仅包含EntitySet
(实体)和{{1} (关系)。在上面的项目中,实现在AssociationSet
类。
由于某些EF版本,EF不再使用JetCreateSqlGenerator
来生成数据库对象,或者更好的是,如果EF Provider提供DbProviderServices
,EF使用该接口,否则EF使用旧版本MigrationSqlGenerator
。 DbProviderServices
提供索引生成和其他迁移实用程序(例如列和表重命名等)。
因此您不会在自定义迁移中看到索引生成,因为您使用的是旧界面。