web-dev-qa-db-ja.com

Entity Framework 5のコードファーストがデータベースを作成しない

Entity Frameworkのコードファーストコンセプトを使用して、新しいデータベースを作成しようとしています。ただし、コードを実行すると、データベースは作成されません(DropCreateDatabaseIfModelChanges設定を使用)。ただし、コードは正常に実行されます。データベースから何かを取得しようとすると、次の例外が表示されます。

enter image description here

私のプロジェクトは、一般的なサービスとリポジトリの構築を備えた別個のDataAccessレイヤーを使用してセットアップされています。したがって、すべてのエンティティ、リポジトリ、およびデータベースコンテキストは、ソリューション内の別のプロジェクトにあります。

global.asaxファイルには、次のコードが含まれています。

Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MyContext>());

新しいデータベースが存在しない場合は、初期化する必要がありますよね?

データベースコンテキストクラスは次のようになります。

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>();
        }
    }
}

インターネット上のいくつかのチュートリアルと記事に従って、このクラスを作成しました。それはすべて私にとって新しいですが、私が見ることができる限り、すべてはこれまでのところ正しいようです。だから今私が使用している2つのエンティティ。それらは「プロジェクト」および「ポートフォリオ」と呼ばれます。彼らはこのように見えます。

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; }
    }

そして

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; }
    }

私が使用しているデータベースは外部サーバーで実行されており、使用しているホスティングプロバイダーに付属しています。 SQL Serverデータベースを起動して実行していますが、データベースへの接続文字列はWebサイトプロジェクトのweb.configにあります。私はすでにデータベースを削除してコードを再作成させようとしましたが、残念ながら機能しませんでした。ここで明らかな何かを見逃していますか?それとも、データベースを作成するためのサーバーへのアクセス権として単純なことでしょうか?

注:Database-Update -Scriptコマンドを実行してSQLコードを生成すると、すべてのテーブルを作成するための正しいSQLステートメントが作成されたようです。

PDATE 1:さて、コメントのおかげでもう少し先に来ました。いくつかの変更を強制するためにエンティティに2つのプロパティを追加し、このようなカスタム初期化子も作成しました。

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);
        }
    }

また、コンテキストのコンストラクターから初期化子を削除したため、このコード行を削除しました。

Database.SetInitializer<MyContext>(new DropCreateDatabaseIfModelChanges<MyContext>());

その後、これら3行をGlobal.asaxファイルに追加しました。

Database.SetInitializer(new ForceDeleteInitializer());
MyContext c = new MyContext();
c.Database.Initialize(true);

デバッグ時に、この例外が発生しています。 enter image description here

これにより、次の情報が得られます:

  • InnerException says:プロバイダーはProviderManifestTokenを返さなかった
  • InnerExceptionのInnerExceptionは次のように述べています。「この操作にはmasterdatabaseへの接続が必要です。元の接続が開かれ、参照が接続から削除されたため、「master」データベースの幅で接続できません。開いていない接続」

これらのアクションの後、データベースにアクセスできないため、ほとんどの場合削除されます。

これについておそらく何ができるでしょうか?私のホスティングプロバイダーが適切なアクセス権を私に与えないため、マスターデータベースにアクセスできない可能性が最も高いでしょう。

21
Rob

他の解決策がなかったため、アプローチを変更することにしました。

最初に自分でデータベースを作成し、正しいSQLユーザーが構成され、アクセスできることを確認しました。

次に、Global.asaxファイルから初期化子とコードを削除しました。その後、パッケージマネージャーコンソールで次のコマンドを実行しました(階層化されたデザインのため、コンソールで正しいプロジェクトを選択する必要があったため)。

Enable-Migrations

移行が有効になり、エンティティに最後の変更を加えた後、以下のコマンドを実行して新しい移行の足場を作りました。

Add-Migration AddSortOrder

移行が作成された後、コンソールで次のコマンドを実行すると、データベースがエンティティで更新されました。

Update-Database -Verbose

移行を実行するときにデータベースをシードできるように、移行を有効にするときに作成されたConfiguraton.csクラスのSeedメソッドをオーバーライドしました。このメソッドの最終コードはこの;

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;
            }
        }

現時点での欠点は、パッケージマネージャーコンソールで2つのコマンド(のみ)を使用して手動で移行する必要があることです。しかし、同時に、これが動的に行われないという事実も、データベースへの望ましくない変更を防ぐことができるため、良いことです。さらに、すべてが完璧に機能します。

13
Rob

詳細な質問については+1。

接続文字列が正しいデータベースを指していることを確認し、データベースにアクセスするために次のような許可属性を追加します。

<add name="PatientContext" providerName="System.Data.SqlClient" connectionString="Server=SQLSERVER2; Database=Patients; uid=PatientUser; password=123456; Integrated Security=False;" />
1
RedAces

初期化する前に、次のコードを実行してデータベースを作成します。

context.Database.CreateIfNotExists();

0
Mohammad Ansari

したがって、最初にコンテキストクラスのコンストラクタパラメータからDb名を削除し、接続文字列にDb_nameを指定してから、ソリューションを再構築し、アプリケーションを実行して、アプリケーション用のデータベースを作成します。

例えば ​​:

コンストラクターパラメーターにDb-Nameを渡していない

public EmployeeContext()
            : base()
        {
            Database.SetInitializer<EmployeeContext>(new DropCreateDatabaseIfModelChanges<EmployeeContext>());
        }

接続文字列では、次のようにDb-nameを渡します。

    <add name="EmployeeContext" connectionString="server=.; database=EFCodeFirstTPHInheritance; uid=sa;[email protected];persistsecurityinfo=True" providerName="System.Data.SqlClient"/>
  </connectionStrings> 
0
Sharad Tiwari