web-dev-qa-db-fra.com

Ne pas créer de base de données Entity Framework 5 en premier

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.

enter image description here

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; enter image description here

Cela me donne les informations suivantes:

  • InnerException dit: Le fournisseur n'a pas renvoyé un ProviderManifestToken
  • InnerException dans InnerException indique: "Pour cette opération, une connexion à la base de données principale est requise. Une connexion ne peut pas être Largeur de la base de données 'master' car la connexion d'origine est Ouverte et les références supprimées de la connexion . Veuillez fournir une connexion non ouverte "

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é.

20
Rob

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.

13
Rob

+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;" />
1
RedAces

avant de l'initialiser, lancez le code suivant pour créer votre base de données:

context.Database.CreateIfNotExists ();

0
Mohammad Ansari

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> 
0
Sharad Tiwari