1

我在我的 web 应用程序中进行了分层设计,具有通用服务和存储库构造。我想先使用代码,这样我就可以对我的实体进行编码,然后创建/更新我的数据库。但是我似乎无法让它工作。我是生成数据库并为其播种的代码优先概念的新手,因此它很可能是显而易见的;-)

我的应用程序设计如下。

  • 网站
  • 网站.DAL
  • Website.TESTS(尚未使用)

website.DAL 项目包含我的通用服务和存储库,以及 DataContext 和我的实体。这个想法是我可以在某个实体的控制器内实例化一个泛型服务。该服务可以包含更多功能来进行计算等。存储库仅用于处理 CRUD 操作。网站项目当然参考了 Website.DAL 项目,并且通过 NuGet 在两个项目中安装了 EF5。

DataContext 如下所示:

using System.Data.Entity;
using System.Web;
using Website.DAL.Entities;

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("MyConnectionstringName")
        {
            //MyContext.Database.Initialize(true);

            //if (HttpContext.Current.IsDebuggingEnabled)
            //{
            //    //Database.SetInitializer<MyContext>(new DatabaseInitializer());
            //    Database.SetInitializer<MyContext>(null);
            //}
            //else
            //{
            //    //Database.SetInitializer<MyContext>(new CreateInitializer());
            //}
        }

        static MyContext()
        {
            Database.SetInitializer<MyContext>(null);
        }

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

        //public void Seed(MyContextContext)
        //{
        //    // Normal seeding goes here

        //    Context.SaveChanges();
        //}
    }
}

我还创建了一个当前为空的 DatabaseInitialiser 类,但我的想法当然是在创建或更新数据库时让它成为我的数据库的种子。

DatabaseInitialiser 类如下所示:

using System.Data.Entity;
using Website.DAL.Model;

namespace Website.DAL
{
    public class DatabaseInitializer : DropCreateDatabaseIfModelChanges<MyContext>
    {
        public DatabaseInitializer()
        {

        }             

        protected override void Seed(MyContextcontext)
        {
            //TODO: Implement code to seed database

            //Save all changes
            context.SaveChanges();
        }
    }
}

由于 GenericService 与问题无关,我将其省略,因为它目前仅直接调用存储库而没有任何特定的商业智能。

使用的通用存储库如下所示。这里的事情仍然需要改进,但它现在有效。

通用存储库

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Website.DAL.Model;
using Website.DAL.RepositoryInterfaces;

namespace Website.DAL.Repositories
{

    public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
    {
        #region Implementation of IRepository<TEntity>

        //protected SceObjectContext DataContext;
        //protected ObjectContext DataContext;
        private MyContext _context;
        //private IObjectSet<T> ObjectSet;
        private DbSet<TEntity> _dbSet;

        public GenericRepository()
        {
            //DataContext = SceObjectContext.Current;
            //DataContext = new ObjectContext("dbConnection");
            _context = new MyContext();
            //ObjectSet = DataContext.CreateObjectSet<T>();
            _dbSet = _context.Set<TEntity>();
        }

        /// <summary>
        /// Inserts a new object into the database
        /// </summary>
        /// <param name="entity">The entity to insert</param>
        public void Insert(TEntity entity)
        {
            //var entitySetName = GetEntitySetName(typeof(T));
            //DataContext.AddObject(entitySetName, entity);
            _dbSet.Add(entity);
        }

        /// <summary>
        /// Deletes the specified entity from the database
        /// </summary>
        /// <param name="entity">The object to delete</param>
        public void Delete(TEntity entity)
        {
            //DataContext.DeleteObject(entity);
            if (_context.Entry(entity).State == System.Data.EntityState.Detached)
            {
                _dbSet.Attach(entity);
            }

            _dbSet.Remove(entity);
        }

        /// <summary>
        /// Saves all pending chances to the database
        /// </summary>
        public void Save()
        {
            _context.SaveChanges();
        }

        /// <summary>
        /// Retrieves the first object matching the specified query.
        /// </summary>
        /// <param name="where">The where condition to use</param>
        /// <returns>The first matching object, null of none found</returns>
        public TEntity First(Expression<Func<TEntity, bool>> @where)
        {
            return _dbSet.FirstOrDefault(where);
        }

        /// <summary>
        /// Gets a list of all objects
        /// </summary>
        /// <returns>An strong typed list of objects</returns>
        public IEnumerable<TEntity> GetAll()
        {
            return _dbSet.AsEnumerable<TEntity>();
        }

        /// <summary>
        /// Returns ans iQueryable of the matching type
        /// </summary>
        /// <returns>iQueryable</returns>
        public IQueryable<TEntity> AsQueryable()
        {
            return _dbSet.AsQueryable();
        }
        #endregion
    }
}

我有两个我创建的实体。投资组合是其中之一,显示在下方。Project 是第二个,它只是一个带有 Id 和一些属性的简单 POCO 类。

投资组合.cs

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

以上所有类都在我的 Website.DAL 项目中维护。我的网站项目中的 Global.asax 包含一些调用初始化程序的代码,据我所知,它应该确保可以在不久的将来完成播种并维护数据库表。

全球.asax

try
{
    //Regenerate database if needed.
    //Database.SetInitializer<MyContext>(new DropCreateDatabaseIfModelChanges<MyContext>());
    //Database.SetInitializer(new DatabaseInitializer());
    Database.SetInitializer(new DropCreateDatabaseIfModelChanges<BorloContext>());
    //Database.SetInitializer<MyContext>(new MigrateDatabaseToLatestVersion<MyContext>());
}
catch (Exception)
{
    throw;
}

只是为了它,我在我的 HomeController 中有一段代码,它应该获取所有投资组合项目的 id。

var list = _portfolioService.GetAll();

通过代码进行调试时会发生以下情况;

  • Global.asax 中的初始化程序代码通过。
  • 调用 databaseinitialiser 的构造函数
  • homecontroller 中的代码不会引发异常。但是,当向“_portfolioService.GetAll();”的调用添加手表时 我收到以下异常;

在此处输入图像描述

我无法弄清楚这里出了什么问题。当然异常不好,但我无法查看内部异常,因为它没有给我一个。我能做些什么来让它工作?或者我想要实现的事情不是不可能的,是否应该将 DAL 层合并到网站中以使代码生成工作?

更新 1:

好的,我在我的上下文中更改了以下行

Database.SetInitializer<MyContext>(null);

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

现在我在调试“_portfolioService.GetAll();”时遇到了这个错误和堆栈跟踪 呼叫家庭控制器

错误:

无法检查模型兼容性,因为数据库不包含模型元数据。只能检查使用 Code First 或 Code First 迁移创建的数据库的模型兼容性。

bij System.Data.Entity.Internal.ModelCompatibilityChecker.CompatibleWithModel(InternalContext internalContext, ModelHashCalculator modelHashCalculator, Boolean throwIfNoMetadata)
   bij System.Data.Entity.Internal.InternalContext.CompatibleWithModel(Boolean throwIfNoMetadata)
   bij System.Data.Entity.Database.CompatibleWithModel(Boolean throwIfNoMetadata)
   bij System.Data.Entity.DropCreateDatabaseIfModelChanges`1.InitializeDatabase(TContext context)
   bij System.Data.Entity.Database.<>c__DisplayClass2`1.<SetInitializerInternal>b__0(DbContext c)
   bij System.Data.Entity.Internal.InternalContext.<>c__DisplayClass8.<PerformDatabaseInitialization>b__6()
   bij System.Data.Entity.Internal.InternalContext.PerformInitializationAction(Action action)
   bij System.Data.Entity.Internal.InternalContext.PerformDatabaseInitialization()
   bij System.Data.Entity.Internal.LazyInternalContext.<InitializeDatabase>b__4(InternalContext c)
   bij System.Data.Entity.Internal.RetryAction`1.PerformAction(TInput input)
   bij System.Data.Entity.Internal.LazyInternalContext.InitializeDatabaseAction(Action`1 action)
   bij System.Data.Entity.Internal.LazyInternalContext.InitializeDatabase()
   bij System.Data.Entity.Internal.InternalContext.Initialize()
   bij System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
   bij System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
   bij System.Data.Entity.Internal.Linq.InternalSet`1.GetEnumerator()
   bij System.Data.Entity.Infrastructure.DbQuery`1.System.Collections.Generic.IEnumerable<TResult>.GetEnumerator()
   bij System.Linq.SystemCore_EnumerableDebugView`1.get_Items()
4

1 回答 1

0

由于没有其他解决方案,我决定改变我的方法。

我首先自己创建了数据库,并确保配置了正确的 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-30T06:34:46.140 回答