zoukankan      html  css  js  c++  java
  • 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方法是事务型方法,若其中出现异常,则整体回滚。

  • 相关阅读:
    消息中间件——RabbitMQ(六)理解Exchange交换机核心概念!
    消息中间件——RabbitMQ(五)快速入门生产者与消费者,SpringBoot整合RabbitMQ!
    消息中间件——RabbitMQ(四)命令行与管控台的基本操作!
    消息中间件——RabbitMQ(三)理解RabbitMQ核心概念和AMQP协议!
    LayUI的基本使用
    Git报错:Your branch is up to date with 'origin/master'.
    Git报错:Please tell me who you are.
    Git报错:Permission denied (publickey)
    在 windows 上安装 git 2.22
    在 windows 上安装 git 2.15
  • 原文地址:https://www.cnblogs.com/cleverJoe/p/5275293.html
Copyright © 2011-2022 走看看