22

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

ここに画像の説明を入力

私のプロジェクトは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.configは Web サイト プロジェクトの中にあります。私はすでにデータベースを削除しようとしましたが、残念ながらうまくいきませんでした。ここで明らかな何かが欠けていますか?それとも、データベースを作成するためのサーバーへのアクセス権のような単純なものでしょうか?

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

更新 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);

デバッグすると、この例外が発生します。 ここに画像の説明を入力

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

  • InnerException は言う: プロバイダーは ProviderManifestToken を返さなかった
  • InnerException の InnerException は次のように述べています。開いていない接続」

これらのアクションの後、データベースにアクセスできなくなるため、おそらく削除されます..

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

4

4 に答える 4

14

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

最初に自分でデータベースを作成し、正しい 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 つのコマンド (のみ) を使用して手動で移行する必要があることです。しかし同時に、これが動的に行われないという事実もまた良いことです。さらに、すべてが完璧に機能します。

于 2013-07-30T10:42:04.587 に答える
2

詳細な質問には+1。

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

<add name="PatientContext" providerName="System.Data.SqlClient" connectionString="Server=SQLSERVER2; Database=Patients; uid=PatientUser; password=123456; Integrated Security=False;" />
于 2013-07-11T19:33:18.940 に答える