bekam ich ein kleines Modell:Warum funktionieren meine EntityFramework 6.1-Indizes, die einen benutzerdefinierten DbInitializer verwenden, nicht?
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
Als ich dies mit EF6.1 in eine Lösung setzen mit diesem Code:
Public Class Thing
Public Property Id As Integer
Public Property Name As String
End Class
A DbContext
passende
Sub Main()
Using db As New Context
Dim t = New Thing With {.Name = "Thingy"}
db.Things.Add(t)
db.SaveChanges()
End Using
End Sub
alles funktioniert wie erwartet. Der 2. Lauf wird eine Ausnahme auslösen, da eine eindeutige Indexverletzung vorliegt.
Leider brauche ich meine Anwendung nicht die ganze DB wegwerfen. Also schrieb ich einen Tisch und Zwänge DbInitializer
wie diese fallen:
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
dieses initializer verwenden, werden meine Indizes schlagen nie die Datenbank. Alles andere funktioniert gut.
ObjectContext.CreateDatabaseScript()
wird keine SQL für die Indizes zurück:
create table [dbo].[Things] (
[Id] [int] not null identity,
[Name] [nvarchar](255) null,
primary key ([Id])
);
Verwendung des Standard DbInitializer
, die SQL an die DB gesendet sieht wie folgt aus:
CREATE TABLE [dbo].[Things] (
[Id] [int] NOT NULL IDENTITY,
[Name] [nvarchar](255),
CONSTRAINT [PK_dbo.Things] PRIMARY KEY ([Id])
)
durch eine andere Anweisung wie folgt folgt:
CREATE UNIQUE INDEX [UniqueOrgUnitName] ON [dbo].[Things]([Name])
Hat jemand einen Einblick Int o warum das nicht funktioniert?
Woher kommt der Index-SQL, wenn er nicht in dem enthalten ist, was CreateDatabaseScript()
zurückgibt?
Die gebündelten EF 'DbInitializer' rufen eine interne 'Database.Create()' - Überladung auf, indem sie einen Parameter vom Typ 'DatabaseExistenceState' verwenden. Wenn ich die public parameterlose Create() 'rufe, bekomme ich eine Ausnahme:" ... kann nicht erstellt werden, da sie bereits existiert ". –
Warum müssen Sie mit MigrationHistory umgehen? Tatsächlich habe ich manchmal ein Problem mit der Validierung (einfach zu sehen, also könnte ich auch mit Indizes haben) und es scheint, dass ich es lösen kann, wenn ich sowohl fließende Schnittstelle als auch Datenannotation verwende, um Entitäten zu konfigurieren (ich weiß, sehr seltsam).Sie könnten versuchen, Datenanmerkungen für Ihre Entität hinzuzufügen. – bubi
Ich erstelle einen MigrationHistory, sodass EntityFramework bemerken wird, dass das Schema aktuell ist. –