我的web应用程序中有一个分层设计,具有通用服务和存储库构造。我想先使用代码,这样我就可以对我的实体进行编码,然后创建/更新我的数据库。但是我似乎无法让它发挥作用。我是代码第一个概念的新手,它生成数据库并播种它,所以它很可能是显而易见的东西; - )
我的应用程序设计如下。
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与问题无关,我会将其遗漏,因为它目前只在没有任何特定商业智能的情况下直接调用存储库。
使用的通用存储库看起来像这样。这里仍然需要改进,但它现在有效。
GenericRepository
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是第二个,它只是一个简单的POCO类,具有Id和一些属性。
Portfolio.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包含一些调用初始化程序的代码,据我所知,应该确保可以在不久的将来完成种子设定并维护数据库表。
Global.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();
通过代码调试时会发生以下情况;
我无法弄清楚这里出了什么问题。当然,例外并不好,但我无法查看内部异常,因为它没有给我一个。我能做些什么才能让这个工作?或者不是我想实现的不可能的事情,是否应该将DAL层合并到网站中以使代码生成工作?
更新1:
好的,我在上下文中更改了以下行
Database.SetInitializer<MyContext>(null);
要
Database.SetInitializer<MyContext>(new DatabaseInitializer());
现在我在调试'_portfolioService.GetAll();'时遇到了这个错误和堆栈跟踪打电话给家庭控制器
错误:
无法检查模型兼容性,因为数据库没有 包含模型元数据。只能检查模型兼容性 使用Code First或Code First Migrations创建的数据库。
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()
答案 0 :(得分:0)
由于没有其他解决方案,我决定改变我的方法。
我自己首先创建了数据库并确保配置了正确的SQL用户并且我有权访问。
然后我从Global.asax文件中删除了初始化程序和代码。之后我在Package Manager控制台中运行了以下命令(因为分层设计我必须在控制台中选择正确的项目);
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个命令手动迁移。但同时,这不会动态发生的事实也很好,因为这可以防止对我的数据库进行有害的更改。此外,一切都很完美。