EntityFramework基础框架搭建

近期学习了关于EntityFramework的基础概念知识,今天开始进行Sample设计及测试,从而深入了解关于EF的使用及知识总结。

        首先进行Sample的环境配置,分别如下图所示:

 

                 

以上两图即此TestSample所搭建的基础环境,右图为数据实体类部分,左图为数据属性约定、数据初始化及配置文件。此Sample主要为搭建环境而非系统内置方法测试,因此实体类的定义非常简单。

1         public class Role
2         {
3             public int ID { get; set; }
4         
5             public string Name { get; set; }
6         
7             public IList<User> Users { get; set; }
8         }

 

       

  public class User
    {
        public int ID { get; set; }

        public string Name { get; set; }

        public IList<Role> Roles { get; set; }

    }

通过App.config文件中的配置,分别设定数据库连接字符串(从而设定数据库位置)、所使用的EF版本号。如下所示:

 

<?xml version="1.0" encoding="utf-8"?>

<configuration>

  <configSections>

        //此处对引用的EF版本信息等进行配置

       <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />

 </configSections>

  //此处设定连接字符串,即对数据库位置及名称进行配置

  <connectionStrings>

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

  </connectionStrings>

 

  <entityFramework>

     //此处设定EntityFramework的默认连接工厂,若未进行连接字符串设定,则需要建立数据库时,将由连接工厂按默认设定进行数据库生成

    <defaultConnectionFactory type="System.Data.Entity.Infrastructure.LocalDbConnectionFactory, EntityFramework">

      <parameters>

        <parameter value="v11.0" />

      </parameters>

    </defaultConnectionFactory>

    //此处设定SqlServer服务提供者

    <providers>

      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />

    </providers>

  </entityFramework>

</configuration>

 

DbContextHelper类内是自定义的为DbContext类提供的扩展方法,本Sample中使用到的方法如下,功能是根据传入的连接字符串,根据EF的连接工厂生成数据连接:

 

        internal static void InitializeConnection(this DbContext context, string connectionString)
                {
                    if ((context == null) || (context.Database == null) || (context.Database.Connection == null))
                        throw new ArgumentException("数据库访问组件未正确初始化。", "context");
                    //获取程序使用的连接工厂
                    var factory = DbProviderServices.GetProviderFactory(context.Database.Connection);
                    var srcBuilder = factory.CreateConnectionStringBuilder();
                    srcBuilder.ConnectionString = context.Database.Connection.ConnectionString;
                    //引入连接字符串
                    var toBuilder = factory.CreateConnectionStringBuilder();
                    toBuilder.ConnectionString = connectionString;
                    //使用连接工厂默认配置,进行数据库连接初始化
                    foreach (string key in srcBuilder.Keys)
                    {
                        if (srcBuilder.ShouldSerialize(key) && !toBuilder.ShouldSerialize(key))
                        {
                            toBuilder.Add(key, srcBuilder[key]);
                        }
                    }
                    context.Database.Connection.ConnectionString = toBuilder.ConnectionString;
                }

 

EntityContext类继承自DbContext类,在其中进行Context的初始化相关方法的定义:

 

public class EntityContext : DbContext

    {

        public const string ConnectionName = "CodeOnly";

 

        static EntityContext()

        {

            Database.SetInitializer<EntityContext>(null);

        }

 

        public EntityContext()

        {

            this.InitializeConnection(GetConnectionStringFromConfiguration());

        }

 

        //也可直接使用语句,但容错效果不好

         //public EntityContext() : base("CodeOnly") { }

 

        public DbSet<User> User_Table { get; set; }

 

        public DbSet<Role> Role_Table { get; set; }

 

        protected override void OnModelCreating(DbModelBuilder modelBuilder)

        {

            base.OnModelCreating(modelBuilder);

            //移除级联删除约定

            modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

            //将自定义的PropertyConfigurationConvention类中的约定进行加载

            modelBuilder.Conventions.Add<PropertyConfigurationConvention>();

            //从程序集中检索所有的Configuration,并进行加载,在本Sample中,即检索到Configuration文件夹中的配置设定文件,并进行加载

            modelBuilder.Configurations.AddFromAssembly(typeof(EntityContext).Assembly);

        }

 

        private string GetConnectionStringFromConfiguration()

        {

            //获取当前程序默认配置文件中的ConnectionStrings结点中的“CodeOnly”行

            //若不为空则返回该行中的"ConnectionString"属性值

            var css = ConfigurationManager.ConnectionStrings[ConnectionName];

            return (css == null ? null : css.ConnectionString);

        }

    }

再来看Configuration文件夹中定义的对两个类的约定配置,以Role实体的约定为例,User实体的约定类似:

 

internal class RoleConfiguration : EntityTypeConfiguration<Role>

    {

        public RoleConfiguration()

        {

            //约定ID属性为自增长

            this.Property(t => t.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

            this.Property(t => t.Name);

            //约定ID属性作为此实体在数据表中的主键

            this.HasKey(t => t.ID);

        }

    }

 

 在UnitTest中,测试方法代码如下:

 

 1 public void TestFirst()
 2 
 3         {
 4 
 5             using (var db = new EntityContext())
 6 
 7             {
 8 
 9                 //若数据库不存在,则根据EntityContext类中通过DbSet所声明的实体进行数据库创建
10 
11                 db.Database.CreateIfNotExists();
12 
13  
14 
15                 //因为Role和User实体均将ID设为整型、主键、自增长,因此在进行Insert时无需进行设定
16 
17                 var role = new Role();
18 
19                 role.Name = "Administrator";
20 
21                 db.Role_Table.Add(role);
22 
23                
24 
25                 var user = new User();
26 
27                 user.Name = "Apollo";
28 
29                 user.Roles = new List<Role> { role };
30 
31  
32 
33                 db.User_Table.Add(user);
34 
35  
36 
37                 //此Assert表示将所有对数据的操作进行对数据库的更新,并返回影响的行数,若大于0说明更新成功
38 
39                 Assert.IsTrue(db.SaveChanges() > 0);
40 
41             }
42 
43         }

 

 

在此案例中,得出以下几点注意事项:

     1.仅在不存在此数据库时,CreateIfNotExists()方法才会发挥作用,创建新数据库,否则将会在执行SaveChanges方法时直接生成SQL操作,并在已有数据库基础上尝试执行,若实体结构与数据表结构不一致,则抛出异常。

    2.EF默认生成的表名为Users,Roles,UserRoles,在UserRoles中默认将字段命名为User_ID,Role_ID,若希望使用自定义数据库中的字段名和表名,需要在Configuration文件中进行单独配置,否则若已有的数据表及字段命名与EF默认不一致,将在SaveChanges方法被调用时抛出异常。

    3.SaveChanges方法是事务型方法,若其中出现异常,则整体回滚。

posted @ 2016-03-14 12:46  大木水可  阅读(680)  评论(0编辑  收藏  举报