EF 的 霸气配置
通过EF 作为操作数据库的工具有一段时间了,也做了几个相对不大的项目,慢慢的也对EF的使用摸索出来了一些规则,虽然说不是技术难点,但是,我说的是但是,能够提高我们开发效率的棉花糖有时我们还是必须要吃的,因为他确实很甜很甜。现在Ef已经更新到6.1.1了,从原来的5.0 到现在也不过是短短的一年多,所以说Ef的生命力还是很强的。什么 你要我对比一下EF和NHibernate的优缺点,这不是本文的重点,我只说一句,EF侧重代码配置,NHibernate 侧重配置文件配置,但是说哪种好,萝卜白菜 各有所爱吧。
刚开始使用EF操作数据表我们是这样使用的,通过在DBContext中添加Dbset<T> 这种形式的属性来实现,但是,我说的是但是,这种方式随着我们的实体Domain越来越多的时候我们不得不一个一个的添加到DbContext中,这不禁让我很苦恼,有没有更好的办法呢?
为了说明的方便,我建立了一个控制台的程序,毕竟EF和具体的项目类型无关。
 1  class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             TestContext testContext = new TestContext();
 6             ///获取数据库表Person中的所有数据 在查询的时候最好加上AsNoTracking 禁止EF跟踪
 7             var personList = testContext.Persons.AsNoTracking().ToList();
 8         }
 9     }
10 
11     public class TestContext : DbContext
12     {
13         private static TestContext _instance;
14 
15         public static TestContext Instance
16         {
17             get
18             {
19                 if (_instance == null)
20                 {
21                     _instance = new TestContext();
22                 }
23                 return _instance;
24             }
25         }
26 
27         private string _connectionString;
28 
29         public string ConnectionString
30         {
31             get
32             {
33                 if (string.IsNullOrWhiteSpace(_connectionString))
34                 {
35                     _connectionString = ConfigurationManager.ConnectionStrings["testConn"].ConnectionString;
36                 }
37                 return _connectionString;
38             }
39             set
40             {
41                 _connectionString = value;
42             }
43         }
44 
45         public TestContext()
46             : base("name=testConn")
47         {
48             _connectionString = ConfigurationManager.ConnectionStrings["testConn"].ConnectionString;
49         }
50         public TestContext(string connectionString)
51             : base(connectionString)
52         {
53 
54         }
55 
56         /// <summary>
57         /// 定义的实体
58         /// </summary>
59         public DbSet<Person> Persons { get; set; }
60     }
61     [Table("Person")]
62     public class Person
63     {
64         public string Name { get; set; }
65 
66         public string Age { get; set; }
67     }
每次添加实体Domain 都要在DbContext 中添加一个对应的属性,很令人苦恼,并且如果属性为string 类型,在数据库中创建的表的长度为max,当然我们可以修改EF的默认约定来让string 类型在数据表中具有一定的长度。我们有没有更好的方式来控制EF创建的数据表呢,并且要易于维护,让所有同事都可以很轻松的掌握。当然,有一个新大陆被发现了。
我们通过反射来找到所有继承自EntityTypeConfiguration的类,这些类就是EF的映射类,我们把这些映射类添加到EF configuration中就可以实现我们的功能,说太多,上代码。
  1  class Program
  2     {
  3         static void Main(string[] args)
  4         {
  5             TestContext testContext = new TestContext();
  6             ///获取数据库表Person中的所有数据 在查询的时候最好加上AsNoTracking 禁止EF跟踪
  7           //  var personList = testContext.Persons.AsNoTracking().ToList();
  8         }
  9     }
 10 
 11     public class TestContext : DbContext
 12     {
 13         private static TestContext _instance;
 14 
 15         public static TestContext Instance
 16         {
 17             get
 18             {
 19                 if (_instance == null)
 20                 {
 21                     _instance = new TestContext();
 22                 }
 23                 return _instance;
 24             }
 25         }
 26 
 27         private string _connectionString;
 28 
 29         public string ConnectionString
 30         {
 31             get
 32             {
 33                 if (string.IsNullOrWhiteSpace(_connectionString))
 34                 {
 35                     _connectionString = ConfigurationManager.ConnectionStrings["testConn"].ConnectionString;
 36                 }
 37                 return _connectionString;
 38             }
 39             set
 40             {
 41                 _connectionString = value;
 42             }
 43         }
 44 
 45         public TestContext()
 46             : base("name=testConn")
 47         {
 48             _connectionString = ConfigurationManager.ConnectionStrings["testConn"].ConnectionString;
 49         }
 50         public TestContext(string connectionString)
 51             : base(connectionString)
 52         {
 53 
 54         }
 55         protected override void OnModelCreating(DbModelBuilder modelBuilder)
 56         {
 57             ///DomainMapping  所在的程序集一定要写对,因为目前在当前项目所以是采用的当前正在运行的程序集 如果你的mapping在单独的项目中 记得要加载对应的assembly
 58             ///这是重点
 59             var typesToRegister = Assembly.GetExecutingAssembly().GetTypes()
 60           .Where(type => !String.IsNullOrEmpty(type.Namespace))
 61           .Where(type => type.BaseType != null && type.BaseType.BaseType != null && type.BaseType.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
 62             foreach (var type in typesToRegister)
 63             {
 64                 dynamic configurationInstance = Activator.CreateInstance(type);
 65                 modelBuilder.Configurations.Add(configurationInstance);
 66             }
 67 
 68             base.OnModelCreating(modelBuilder);
 69         }
 70 
 71  
 72     }
 73 
 74     public class BaseDomain
 75     {
 76 
 77     }
 78     [Table("Person")]
 79     public class Person
 80     {
 81         public string ID { get; set; }
 82         public string Name { get; set; }
 83 
 84         public string Age { get; set; }
 85     }
 86 
 87     public class PersonMapping : BaseDomainMapping<Person>
 88     {
 89         public override void Init()
 90         {
 91             this.ToTable(" 
                    
                
 
