用Entities Framework实现代码优先和依赖注入所遇到的问题总结

最近在搞毕业设计,底层到EF来实现与数据库的连接。由于是第一次用EF来做项目,遇到了种种特别奇怪的出错。

现在,总结自己所遇到的问题,方便以后避免。

第一就是要引用两个包:

用Nuget包引入:Moq和Ninject 

以上两个包用于实现依赖注入。

第二EFDbContext里的实体要和数据库里的表致,不然就会出现,EFDbContext修改了数据库的数据,而数据库里的数据却没有被修改,总之就是要匹配。

View Code
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Data.Entity;
 6 using System.Data.Objects;
 7 using System.Data;
 8 
 9 namespace DAL.Entities
10 {
11     public class EFDbContext : DbContext
12     {
13         public DbSet<Account> Account { get; set; }
14         public DbSet<Address> Address { get; set; }
15         public DbSet<Book> Book { get; set; }
16         public DbSet<BookCart> BookCart { get; set; }
17         public DbSet<Cart> Cart { get; set; }
18         public DbSet<Category> Category { get; set; }
19         public DbSet<City> City { get; set; }
20         public DbSet<Menu> Menu { get; set; }
21         public DbSet<Orders> Orders { get; set; }
22         public DbSet<Province> Province { get; set; }
23     }
24 }

特别是注意一点:就是表名会在其类名上加上字符“s”,我也还没有找出是什么原因。所以加上就不会报错。

对应的数据库如下图:

最后就是配置一点要写对:

 <add name="EFDbContext" connectionString="Data Source=.;Initial Catalog=BookStore;Integrated Security=True" providerName="System.Data.SqlClient" />

第五步:更改数据模型

随着我们应用程序开发的推进,我们将继续改进和重构我们的模型。EF 代码优先类库包括一些很好的开发功能,这使我们在开发数据库时更容易协调某些改进。

给Dinner(餐会)模型添加一个新的属性

让我们对我们的Dinner类做一个简单的修改,更具体的说,我们将给Dinner类添加一个新的“Country”属性。

做完改动,让我们在Virtual Studio中按下F5按钮,重新编译并运行应用程序。将会看到下面的这些错误信息:

这些错误信息之所以出现,是因为我们修改了Dinner类的结构定义,我们的模型对象现在已经不再和数据库中自动创建的Dinners表一致了。

当EF自动地为你创建数据库时,默认地会增加一个“EdmMetadata”表,这个表用来记录自动创建数据库时使用的模型对象的形状。

当EF发现你修改过模型对象,并且和之前自动创建的数据库不再同步时,就会出现上面的错误消息。

也有可能就是在系统表里多出一个表格,应该是系统生成的:

所以如果出现这样的问题,就先到数据库看下是不是多了表。

重新同步数据模型类到数据库

我们有很多同步模型对像和数据库的方式:

  • 我们可以手动地更新数据库中的结构(Schema)让它们保持一致。
  • 我们也可以先删除数据库文件,然后重新运行应用程序,让EF自动重新创建数据库。
  • 我们也可以开启EF 代码优先功能,当数据模型发生任何改变时能够自动更新数据库 。

下面,让我们在NerdDinner应用程序中看看如何使用最后一种的自动更新的方式。

当模型对象发生变化时重新创建数据库(RecreateDatabaseIfModelChanges)功能

在EF 代码优先类库的CTP 4版本中包括了一个非常有用的开发时development-time)功能,它允许你在任意时刻修改数据模型类,自动重建数据库。当你开启这项功能的时候,EF能够识别用来创建数据库的类模型在何时被改动,何时可以重建你的数据库以匹配新的模型类——你不需要做任何手工操作。

这项功能在你刚开发一个应用程序时特别实用,因为它为你快速地重构你的模型代码带来了很大的自由度和灵活性——你根本不用去手动地保持数据库结构的同步。它特别适合SQL CE,因为SQL CE是一个基于文件的数据库而且可以随时在运行时删除和创建。这使得开发流程变得不可思议的流畅。

启用这项功能最简单的方法就是在Global.asax类中的Application_Start()事件处理函数中加上Database.SetInitializer()方法的调用。

这个调用告诉EF当数据模型发生任何变化时,重建NerdDinners.sdf数据库以匹配NerdDinners类。现在当我们重新运行应用程序的时候,再也不会出现提示说类模型和数据库不匹配的错误信息了。反而,EF会自动重建数据库以匹配新的数据模型类,我们的应用程序会正常运行:

 

防止表名生成带“s”

创建一个名为 DAL 的文件夹,在这个文件夹中创建名为 SchoolContext 的类,使用下面的代码替换原有的代码。

复制代码
using System;
using System.Collections.Generic;
using System.Data.Entity;
using ContosoUniversity.Models;
using System.Data.Entity.ModelConfiguration.Conventions;
namespace ContosoUniversity.Models
{
public class SchoolContext
: DbContext
{
public DbSet<Student> Students { get; set; }
public DbSet<Enrollment> Enrollments { get; set; }
public DbSet<Course> Courses { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
}
}
}
复制代码

这段代码使用 DbSet 类型的属性定义每一个实体集。在 EF 术语中,一个实体集典型地关联到一个数据库中的表,一个实体关联到表中的一行。

在 OnModelCreating 方法中的代码防止数据库中的表名被多元化。如果没有这样处理的话,生成的表将会被命名为 Students,Courses 和 Enrollments。现在,表名将会被命名为 Student,Course 和 Enrollment。开发者可以决定表名是否被多元化。这个教程使用单数模式,但是重要的是你可以这行代码来选择喜欢的模式。

 

第三写下依赖注入的实现过程

首先要扩展下控制器

代码如下

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Ninject;
using Moq;
using System.Web.Routing;
using System.Web.Mvc;
using DAL.Concrete.Framework;
using DAL.Entities;
using IBLL.Framework;
using BLL.Framework;



namespace BookStoreUI.Infrastructure
{
    public class NinjectControllerFactory : DefaultControllerFactory
    {
        private IKernel ninjectKernel;

        public NinjectControllerFactory()
        {
            ninjectKernel = new StandardKernel();

            AddBindins();

        }

        protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            return controllerType == null ? null : (IController)ninjectKernel.Get(controllerType);
        }

        //绑定数据
        private void AddBindins()
        {
            //Mock<IProductRepository> mock = new Mock<IProductRepository>();

            //mock.Setup(h => h.Products).Returns(
            //    new List<Product> { 
            //    new Product{Name="FootBall",Price=25 },
            //    new Product{Name="Surf Board",Price=179},
            //    new Product{Name="Running shoes" ,Price=95}              
            //    }.AsQueryable());

            //this.ninjectKernel.Bind<IProductRepository>().ToConstant(mock.Object);


            //采用数据库中的数据来显示,所以要把上面的注释掉,这里就写自己的要实现注入的方法和接口
            this.ninjectKernel.Bind<IAccountBLL>().To<AccountBLL>();
        }
    }
}

  然后要Gobal.asp.cs下面加载这个方法使得程序运行开始就知道控制器被扩展。

    不然重写控制器时就出出错。

代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using BookStoreUI.Infrastructure;
using System.Data.Entity;
using DAL.Entities;

namespace BookStoreUI
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            //Database.SetInitializer<EFDbContext>(null);
            //我们需要注册NinjectControllerFactory到MVC框架,所以我们也需要在Global.asax.cs里给它注册进去
            ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory());
        }
    }
}

  

最后在控制器里就可以实现你所用的注入方法。

直接上代码:

View Code
 1 using IBLL.Framework;
 2 using DAL.Entities;
 3 
 4 namespace BookStoreUI.Controllers
 5 {
 6     public class AccountController : Controller
 7     {
 8         private IAccountBLL iAccountBLL;
 9 
10         public AccountController(IAccountBLL accountBLL)
11         {
12             iAccountBLL = accountBLL;
13         }
14 
15         public ActionResult Index()
16         {
17             return View();
18         }
19 
20         [HttpPost]
21         public ActionResult Index(LoginViewModel model)
22         {
23             //验证码验证
24             if (Session["__VCode"] == null || (Session["__VCode"] != null
25                 && model.ValidateCode != Session["__VCode"].ToString()))
26             {
27                 ModelState.AddModelError("ValidateCode", "验证码出错");
28                 return View();
29             }
30 
31             if (ModelState.IsValid)
32             {
33                 Account account = iAccountBLL.ValidateAccount(model.Account.UserName, model.Account.PassWord);
34 
35                 //登录是否成功
36                 if (account != null)
37                 {
38                     return RedirectToAction("BackIndex", "BackHome");
39                 }
40             }
41 }
42 }

 

 

posted @ 2012-09-15 16:03  Buu  阅读(632)  评论(0编辑  收藏  举报