J'essaie de créer une nouvelle base de données en utilisant le concept de code premier Entity Framework. Cependant, lors de l'exécution du code, la base de données n'est pas créée (à l'aide du paramètre DropCreateDatabaseIfModelChanges
), bien que le code fonctionne correctement. Je vois l'exception suivante lorsque j'essaie d'obtenir quelque chose de la base de données.
Mon projet est configuré à l'aide d'une couche DataAccess
distincte avec un service générique et une construction de référentiel. Ainsi, toutes mes entités, le référentiel et le contexte de la base de données font partie d'un projet distinct de la solution.
Mon fichier global.asax
contient le code suivant.
Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MyContext>());
Cela devrait initialiser une nouvelle base de données si ce n’est pas là, non?
Ma classe de contexte de base de données ressemble à ceci;
namespace Website.DAL.Model
{
public class MyContext : DbContext
{
public IDbSet<Project> Projects { get; set; }
public IDbSet<Portfolio> Portfolios { get; set; }
/// <summary>
/// The constructor, we provide the connectionstring to be used to it's base class.
/// </summary>
public MyContext()
: base("MyConnectionString")
{
}
static MyContext()
{
try
{
Database.SetInitializer<MyContext>(new DropCreateDatabaseIfModelChanges<MyContext>());
}
catch (Exception)
{
throw;
}
}
/// <summary>
/// This method prevents the plurarization of table names
/// </summary>
/// <param name="modelBuilder"></param>
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.PluralizingTableNameConvention>();
}
}
}
J'ai créé ce cours après plusieurs tutoriels et articles sur Internet. C'est tout nouveau pour moi, mais pour autant que je sache, tout semble correct jusqu'à présent. Alors maintenant, les deux entités que j'utilise. Ils s'appellent 'Projet' et 'Portfolio'. Ils ressemblent à ceci;
public class Portfolio
{
[Key]
public Guid Id { get; set; }
public String Name { get; set; }
public DateTime StartDate { get; set; }
public DateTime? EndDate { get; set; }
public bool IsPublished { get; set; }
public virtual ICollection<Project> Projects { get; set; }
}
Et
public class Project
{
[Key]
public Guid Id { get; set; }
public DateTime StartDate { get; set; }
public DateTime? EndDate { get; set; }
public bool IsPublished { get; set; }
public String Title { get; set; }
}
La base de données que j'utilise est exécutée sur un serveur externe. Elle est fournie avec le fournisseur d'hébergement que j'utilise. Une base de données SQL Server est opérationnelle et la chaîne de connexion à la base de données se trouve dans le web.config
du projet de site Web. J'ai déjà essayé de supprimer la base de données et de laisser le code le recréer, ce qui n'a malheureusement pas fonctionné. Est-ce que je manque quelque chose d'évident ici? Ou pourrait-il être une simple chose que les droits d’accès au serveur pour créer des bases de données?
Remarque: lorsque j'exécute la commande Database-Update -Script
pour générer du code SQL, il semble que les instructions SQL correctes pour créer toutes les tables soient créées.
MISE À JOUR 1: .__ D'accord, grâce à certains commentaires, je suis un peu plus loin. J'ai ajouté deux propriétés à mes entités pour imposer certaines modifications et j'ai également créé un initialiseur personnalisé comme celui-ci.
public class ForceDeleteInitializer : IDatabaseInitializer<MyContext>
{
private readonly IDatabaseInitializer<MyContext> _initializer = new DropCreateDatabaseIfModelChanges<MyContext>();
public ForceDeleteInitializer()
{
//_initializer = new ForceDeleteInitializer();
}
public void InitializeDatabase(MyContext context)
{
//This command is added to prevent open connections. See http://stackoverflow.com/questions/5288996/database-in-use-error-with-entity-framework-4-code-first
context.Database.ExecuteSqlCommand("ALTER DATABASE borloOntwikkel SET SINGLE_USER WITH ROLLBACK IMMEDIATE");
_initializer.InitializeDatabase(context);
}
}
J'ai également supprimé l'initialiseur du constructeur de mon contexte, donc cela signifie que j'ai supprimé cette ligne de code;
Database.SetInitializer<MyContext>(new DropCreateDatabaseIfModelChanges<MyContext>());
Après cela, j'ai ajouté ces trois lignes à mon fichier Global.asax;
Database.SetInitializer(new ForceDeleteInitializer());
MyContext c = new MyContext();
c.Database.Initialize(true);
Lors du débogage, je reçois maintenant cette exception;
Cela me donne les informations suivantes:
Après cette action, la base de données est inaccessible, donc probablement supprimée.
Que peut-on éventuellement faire à ce sujet? Il est fort probable que je ne puisse pas accéder à la base de données principale car mon fournisseur d’hébergement ne me donnera pas le droit d’accès approprié.
Comme aucune autre solution n'est venue, j'ai décidé de changer mon approche.
J'ai tout d'abord créé la base de données moi-même et je me suis assuré que le bon utilisateur SQL était configuré et que j'avais accès.
Ensuite, j'ai supprimé l'initialiseur et le code du fichier Global.asax. Après cela, j'ai exécuté la commande suivante dans la console du gestionnaire de packages (depuis la conception en couches, je devais sélectionner le bon projet dans la console);
Enable-Migrations
Une fois les migrations activées et les modifications de dernière minute apportées à mes entités, j'ai exécuté la commande ci-dessous pour échafauder une nouvelle migration.
Add-Migration AddSortOrder
Une fois mes migrations créées, j'ai exécuté la commande suivante dans la console et le tour est joué, la base de données a été mise à jour avec mes entités.
Update-Database -Verbose
Pour pouvoir initialiser la base de données lors de l'exécution de la migration, j'ai remplacé la méthode Seed dans ma classe Configuraton.cs, qui a été créée lors de l'activation des migrations. Le code final dans cette méthode est comme ceci;
protected override void Seed(MyContext context)
{
// This method will be called after migrating to the latest version.
//Add menu items and pages
if (!context.Menu.Any() && !context.Page.Any())
{
context.Menu.AddOrUpdate(new Menu()
{
Id = Guid.NewGuid(),
Name = "MainMenu",
Description = "Some menu",
IsDeleted = false,
IsPublished = true,
PublishStart = DateTime.Now,
LastModified = DateTime.Now,
PublishEnd = null,
MenuItems = new List<MenuItem>()
{
new MenuItem()
{
Id = Guid.NewGuid(),
IsDeleted = false,
IsPublished = true,
PublishStart = DateTime.Now,
LastModified = DateTime.Now,
PublishEnd = null,
Name = "Some menuitem",
Page = new Page()
{
Id = Guid.NewGuid(),
ActionName = "Some Action",
ControllerName = "SomeController",
IsPublished = true,
IsDeleted = false,
PublishStart = DateTime.Now,
LastModified = DateTime.Now,
PublishEnd = null,
Title = "Some Page"
}
},
new MenuItem()
{
Id = Guid.NewGuid(),
IsDeleted = false,
IsPublished = true,
PublishStart = DateTime.Now,
LastModified = DateTime.Now,
PublishEnd = null,
Name = "Some MenuItem",
Page = new Page()
{
Id = Guid.NewGuid(),
ActionName = "Some Action",
ControllerName = "SomeController",
IsPublished = true,
IsDeleted = false,
PublishStart = DateTime.Now,
LastModified = DateTime.Now,
PublishEnd = null,
Title = "Some Page"
}
}
}
});
}
if (!context.ComponentType.Any())
{
context.ComponentType.AddOrUpdate(new ComponentType()
{
Id = Guid.NewGuid(),
IsDeleted = false,
IsPublished = true,
LastModified = DateTime.Now,
Name = "MyComponent",
PublishEnd = null,
PublishStart = DateTime.Now
});
}
try
{
// Your code...
// Could also be before try if you know the exception occurs in SaveChanges
context.SaveChanges();
}
catch (DbEntityValidationException e)
{
//foreach (var eve in e.EntityValidationErrors)
//{
// Console.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
// eve.Entry.Entity.GetType().Name, eve.Entry.State);
// foreach (var ve in eve.ValidationErrors)
// {
// Console.WriteLine("- Property: \"{0}\", Error: \"{1}\"",
// ve.PropertyName, ve.ErrorMessage);
// }
//}
//throw;
var outputLines = new List<string>();
foreach (var eve in e.EntityValidationErrors)
{
outputLines.Add(string.Format(
"{0}: Entity of type \"{1}\" in state \"{2}\" has the following validation errors:",
DateTime.Now, eve.Entry.Entity.GetType().Name, eve.Entry.State));
foreach (var ve in eve.ValidationErrors)
{
outputLines.Add(string.Format(
"- Property: \"{0}\", Error: \"{1}\"",
ve.PropertyName, ve.ErrorMessage));
}
}
System.IO.File.AppendAllLines(@"c:\temp\errors.txt", outputLines);
throw;
}
}
L'inconvénient pour le moment est que je dois migrer manuellement avec (seulement) 2 commandes dans la console du gestionnaire de paquets. Mais en même temps, le fait que cela ne se produise pas de manière dynamique est également positif, car cela évite éventuellement des modifications indésirables de ma base de données. En outre, tout fonctionne parfaitement.
+1 pour la question détaillée.
Vérifiez que votre chaîne de connexion pointe vers la bonne base de données et ajoutez les attributs d'autorisation suivants pour accéder à votre base de données:
<add name="PatientContext" providerName="System.Data.SqlClient" connectionString="Server=SQLSERVER2; Database=Patients; uid=PatientUser; password=123456; Integrated Security=False;" />
avant de l'initialiser, lancez le code suivant pour créer votre base de données:
context.Database.CreateIfNotExists ();
Donc, commencez par supprimer le nom de la base de données du paramètre constructeur de la classe de contexte et indiquez nom_bd sur la chaîne de connexion, puis essayez de reconstruire votre solution et exécutez l'application qui va créer la base de données pour votre application.
Par exemple :
Je ne passe pas le nom de base sur le paramètre constructeur
public EmployeeContext()
: base()
{
Database.SetInitializer<EmployeeContext>(new DropCreateDatabaseIfModelChanges<EmployeeContext>());
}
et sur la chaîne de connexion, je passe le nom de base de données comme ci-dessous.
<add name="EmployeeContext" connectionString="server=.; database=EFCodeFirstTPHInheritance; uid=sa;Password=crius@123;persistsecurityinfo=True" providerName="System.Data.SqlClient"/>
</connectionStrings>