Nous avons un projet sous SCM. Lorsque je le construit à partir de ma machine et que je le publie sur un serveur distant via msdeploy, tout fonctionne correctement.
Lorsque mon collègue tente la même chose avec le même projet, fraîchement tiré du GDS, sur le framework d'entité de serveur distant 4.3.1 DbMigrator
jette:
La migration automatique n'a pas été appliquée car cela entraînerait une perte de données.
En fait, il semble que la personne qui effectue la publication initiale sur le serveur distant soit "gagnante". Si nous laissons la base de données sur le serveur distant, mon colléguegue peut publier et je suis bloqué. Mes publications entraînent la même erreur ci-dessus.
La configuration de DbMigrator
ressemble à ceci:
var dbMgConfig = new DbMigrationsConfiguration()
{
AutomaticMigrationsEnabled = true,
//***DO NOT REMOVE THIS LINE,
//DATA WILL BE LOST ON A BREAKING SCHEMA CHANGE,
//TALK TO OTHER PARTIES INVOLVED IF THIS LINE IS CAUSING PROBLEMS
AutomaticMigrationDataLossAllowed=false,
//***DO NOT REMOVE THIS LINE,
ContextType = typeof(TPSContext),
MigrationsNamespace = "TPS.Migrations",
MigrationsAssembly = Assembly.GetExecutingAssembly()
};
Je suppose que cela a quelque chose à voir avec la nouvelle table __MigrationHistory
et avec la longue chaîne hexagonale à la recherche désagréable stockée dans ses lignes.
Je ne veux pas assumer l'entière responsabilité de publier pour vivre. Que puis-je rechercher?
Nous avons changé notre code de:
dbMgConfig.AutomaticMigrationDataLossAllowed = false;
var mg = new DbMigrator(dbMgConfig);
mg.Update(null);
à
dbMgConfig.AutomaticMigrationDataLossAllowed = true;
var mg = new DbMigrator(dbMgConfig);
var scriptor = new MigratorScriptingDecorator(mg);
string script = scriptor.ScriptUpdate(sourceMigration: null, targetMigration: null);
throw new Exception(script);
afin que nous puissions observer les modifications apportées par DbMigrator
sur le serveur distant.
Dans le cas décrit au début de cette question (un collègue crée un téléchargement qui crée une base de données, suivi de ce que je crée un téléchargement généré à partir de la même source sur une machine différente), les instructions SQL suivantes sont générées:
ALTER TABLE [GalleryImages] DROP CONSTRAINT [FK_GalleryImages_Galleries_Gallery_Id]
ALTER TABLE [GalleryImages] DROP CONSTRAINT [FK_GalleryImages_Images_Image_Id]
ALTER TABLE [UserLightboxes] DROP CONSTRAINT [FK_UserLightboxes_Users_User_Id]
ALTER TABLE [UserLightboxes] DROP CONSTRAINT [FK_UserLightboxes_Lightboxes_Lightbox_Id]
ALTER TABLE [ImageLightboxes] DROP CONSTRAINT [FK_ImageLightboxes_Images_Image_Id]
ALTER TABLE [ImageLightboxes] DROP CONSTRAINT [FK_ImageLightboxes_Lightboxes_Lightbox_Id]
DROP INDEX [IX_Gallery_Id] ON [GalleryImages]
DROP INDEX [IX_Image_Id] ON [GalleryImages]
DROP INDEX [IX_User_Id] ON [UserLightboxes]
DROP INDEX [IX_Lightbox_Id] ON [UserLightboxes]
DROP INDEX [IX_Image_Id] ON [ImageLightboxes]
DROP INDEX [IX_Lightbox_Id] ON [ImageLightboxes]
CREATE TABLE [ImageGalleries] (
[Image_Id] [int] NOT NULL,
[Gallery_Id] [int] NOT NULL,
CONSTRAINT [PK_ImageGalleries] PRIMARY KEY ([Image_Id], [Gallery_Id])
)
CREATE TABLE [LightboxImages] (
[Lightbox_Id] [int] NOT NULL,
[Image_Id] [int] NOT NULL,
CONSTRAINT [PK_LightboxImages] PRIMARY KEY ([Lightbox_Id], [Image_Id])
)
CREATE TABLE [LightboxUsers] (
[Lightbox_Id] [int] NOT NULL,
[User_Id] [int] NOT NULL,
CONSTRAINT [PK_LightboxUsers] PRIMARY KEY ([Lightbox_Id], [User_Id])
)
CREATE INDEX [IX_Image_Id] ON [ImageGalleries]([Image_Id])
CREATE INDEX [IX_Gallery_Id] ON [ImageGalleries]([Gallery_Id])
CREATE INDEX [IX_Lightbox_Id] ON [LightboxImages]([Lightbox_Id])
CREATE INDEX [IX_Image_Id] ON [LightboxImages]([Image_Id])
CREATE INDEX [IX_Lightbox_Id] ON [LightboxUsers]([Lightbox_Id])
CREATE INDEX [IX_User_Id] ON [LightboxUsers]([User_Id])
DROP TABLE [GalleryImages]
DROP TABLE [UserLightboxes]
DROP TABLE [ImageLightboxes]
ALTER TABLE [ImageGalleries] ADD CONSTRAINT [FK_ImageGalleries_Images_Image_Id] FOREIGN KEY ([Image_Id]) REFERENCES [Images] ([Id]) ON DELETE CASCADE
ALTER TABLE [ImageGalleries] ADD CONSTRAINT [FK_ImageGalleries_Galleries_Gallery_Id] FOREIGN KEY ([Gallery_Id]) REFERENCES [Galleries] ([Id]) ON DELETE CASCADE
ALTER TABLE [LightboxImages] ADD CONSTRAINT [FK_LightboxImages_Lightboxes_Lightbox_Id] FOREIGN KEY ([Lightbox_Id]) REFERENCES [Lightboxes] ([Id]) ON DELETE CASCADE
ALTER TABLE [LightboxImages] ADD CONSTRAINT [FK_LightboxImages_Images_Image_Id] FOREIGN KEY ([Image_Id]) REFERENCES [Images] ([Id]) ON DELETE CASCADE
ALTER TABLE [LightboxUsers] ADD CONSTRAINT [FK_LightboxUsers_Lightboxes_Lightbox_Id] FOREIGN KEY ([Lightbox_Id]) REFERENCES [Lightboxes] ([Id]) ON DELETE CASCADE
ALTER TABLE [LightboxUsers] ADD CONSTRAINT [FK_LightboxUsers_Users_User_Id] FOREIGN KEY ([User_Id]) REFERENCES [Users] ([Id]) ON DELETE CASCADE
CREATE TABLE [__MigrationHistory] (
[MigrationId] [nvarchar](255) NOT NULL,
[CreatedOn] [datetime] NOT NULL,
[Model] [varbinary](max) NOT NULL,
[ProductVersion] [nvarchar](32) NOT NULL,
CONSTRAINT [PK___MigrationHistory] PRIMARY KEY ([MigrationId])
)
BEGIN TRY
EXEC sp_MS_marksystemobject '__MigrationHistory'
END TRY
BEGIN CATCH
END CATCH
INSERT INTO [__MigrationHistory] ([MigrationId], [CreatedOn], [Model], [ProductVersion]) VALUES ('201203030113082_AutomaticMigration', '2012-03-03T01:13:08.986Z', 0x[removedToShortenPost], '4.3.1')
Comme on peut le constater, la raison pour laquelle DbMigrator
lance est parce qu'il tente de renommer 3 tables utilisées pour joindre plusieurs relations en inversant les noms des tables qu'elles relient, par exemple GalleryImages
à ImageGalleries
ou UserLightboxes
à LightboxUsers
.
Cela ressemble à un bug dans EF 4.3 où la dénomination des tables "association" semble être d'un ordre indéterminé. Étant donné que l'ordre des noms pour ces types de tables semble être indéfini/indéterminé, nous avons abordé cette question sous un angle différent, en utilisant l'API fluide pour forcer EF à utiliser le nommage cohérent entre les générations de différentes machines:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder
.Entity<Gallery>()
.HasMany(p => p.Images)
.WithMany(p => p.Galleries)
.Map(c =>
{
c.MapLeftKey("Gallery_Id");
c.MapRightKey("Image_Id");
c.ToTable("GalleryImages");
});
modelBuilder
.Entity<User>()
.HasMany(p => p.Lightboxes)
.WithMany(p => p.Users)
.Map(c =>
{
c.MapLeftKey("User_Id");
c.MapRightKey("Lightbox_Id");
c.ToTable("UserLightboxes");
});
modelBuilder
.Entity<Image>()
.HasMany(p => p.Lightboxes)
.WithMany(p => p.Images)
.Map(c =>
{
c.MapLeftKey("Image_Id");
c.MapRightKey("Lightbox_Id");
c.ToTable("ImageLightboxes");
});
}
Avec cela en place, l'erreur disparaît maintenant.
public Configuration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = true;
}
Je reçois la même erreur, j'ai donc généré un script et je l'ai exécuté dans l'analyseur de requêtes. Il s’agit d’un problème de longueur:
Attention! La longueur maximale de la clé est de 900 octets. L'index 'PK_dbo .__ MigrationHistory' a une longueur maximale de 1534 octets. Pour certaines combinaisons de valeurs importantes, l'opération d'insertion/mise à jour échouera.
Il semble que l'équipe EntityFramework en soit consciente:
http://entityframework.codeplex.com/workitem/1216
Je ne sais pas quels problèmes cela va causer .....
J'ai aussi rencontré ce problème. Bizarrement, la table en question ne contient absolument aucune donnée, c’est-à-dire qu’elle est vide, ce que Code First ne semble même pas vérifier lorsqu’il signale que s’il appliquait les migrations, des pertes de données surviendraient.
Je viens d'avoir une erreur très étrange semblable à celle-ci pour Entity Framework 6.2.0.
Configuration.cs:
public class Configuration : DbMigrationsConfiguration<ApplicationDbContext>
{
public Configuration()
{
AutomaticMigrationsEnabled = false;
AutomaticMigrationDataLossAllowed = false;
}
...
}
Le code ci-dessous a provoqué une StackOverflowException
sur une machine mais a bien fonctionné sur une autre.
var migrator = new DbMigrator(new Configuration());
if (migrator.GetPendingMigrations().Any())
{
migrator.Update();
}
Résolu en améliorant comme ceci à la place:
Database.SetInitializer(new MigrateDatabaseToLatestVersion<ApplicationDbContext, Configuration>());