EF实体对象解耦

为了达到模块间最小耦合,单模块业务数据不与其他模块发生关系。在操作数据库的时候,采用EF泛型操作。但泛型操作不好实现联表,经过一晚的试验发现了一种定义数据库上下文并联表的方式。

1.实体对象定义。实体对象可能存在于不同的业务模块中。他们之间是相互不知道对方存在的。

 1     public class User
 2     {
 3         [Key]
 4         [MaxLength(50)]
 5         public string userId { get; set; }
 6         [MaxLength(50)]
 7         public string userName { get; set; }
 8         public int age { get; set; }
 9         public string sex { get; set; }
10     }
11 
12     public class Order
13     {
14         [Key]
15         [MaxLength(50)]
16         public string orderId { get; set; }
17         public DateTime createTime { get; set; }
18         public string userId { get; set; }
19 
20         public string goodsId { get; set; }
21     }
22 
23     public class Goods
24     {
25         [Key]
26         [MaxLength(50)]
27         public string goodsId { get; set; }
28         public decimal price { get; set; }
29         public float weight { get; set; }
30     }

2.DbContext定义

  1     /// <summary>
  2     /// 基础的数据库操作类,
  3     /// 定义了所有的表结构,定义了数据迁移方案
  4     /// </summary>
  5     public class DbHelper : DbContext
  6     {
  7         static List<Type> tList;
  8 
  9         static DbHelper()
 10         {
 11             //也可以搜索所有程序集里面需要映射表的类型,这样就不需要外部传入了。
 12         }
 13 
 14         /// <summary>
 15         /// 初始化DB,该方法只需要被调用一次
 16         /// 总的说来,必须要在一开始就知道有哪些类型是要进行表映射的。(准确的说,只要在联表调用之前将对应类型在EF中注册过就可以。使用DbHelper<E>会将新的类型注册到EF,即便这个类型没有在此处统一注册★)
 17         /// </summary>
 18         /// <param name="eTypeList">需要关联的实体类对象</param>
 19         public static void InitDbHelper(List<Type> eTypeList=null)
 20         {
 21             tList = eTypeList ?? tList;
 22             using (DbHelper db = new Db.DbHelper())
 23             {
 24                 try
 25                 {
 26                     db.Set<string>().Add("");
 27                 }
 28                 catch (InvalidOperationException ex)
 29                 {
 30                 }
 31             }
 32 
 33         }
 34 
 35         public DbHelper() : base("defaultConnect")
 36         {
 37             System.Data.Entity.Database.SetInitializer(new MigrateDatabaseToLatestVersion<DbHelper, Configuration<DbHelper>>());
 38         }
 39 
 40         public DbHelper(string connectionName= "defaultConnect") : base(connectionName)
 41         {
 42             System.Data.Entity.Database.SetInitializer(new MigrateDatabaseToLatestVersion<DbHelper, Configuration<DbHelper>>());
 43         }
 44         protected override void OnModelCreating(DbModelBuilder modelBuilder)
 45         {
 46             if(tList != null)
 47             {
 48                 tList.ForEach(f=>{
 49                     modelBuilder.RegisterEntityType(f);
 50                 });
 51             }
 52             //modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
 53             base.OnModelCreating(modelBuilder);
 54         }
 55     }
 56 
 57     /// <summary>
 58     /// 数据迁移设置
 59     /// </summary>
 60     /// <typeparam name="T"></typeparam>
 61     public class Configuration<T> : DbMigrationsConfiguration<T> where T : DbContext
 62     {
 63         public Configuration()
 64         {
 65             AutomaticMigrationsEnabled = true; // 启用自动迁移功能
 66             AutomaticMigrationDataLossAllowed = true; // 允许自动删字段,危险但是不加这个不能重命名字段
 67         }
 68     }
 69     public class DbHelper<E> : DbContext where E : class
 70     {
 71         public DbHelper(string connectionName = "defaultConnect") : base(connectionName)
 72         {
 73         }
 74 
 75         private DbSet<E> Data { get; set; }
 76     }
 77     public class DbHelper<E1,E2>:DbContext where E1:class where E2:class
 78     {
 79         public DbHelper(string connectionName = "defaultConnect") : base(connectionName)
 80         {
 81         }
 82         
 83         private DbSet<E1> Data1{ get; set; }
 84         private DbSet<E2> Data2 { get; set; }
 85 
 86     }
 87 
 88     /// <summary>
 89     /// 如果超出了这里定义的实体个数,可以由外部自行定义DbHelper。
 90     /// </summary>
 91     /// <typeparam name="E1"></typeparam>
 92     /// <typeparam name="E2"></typeparam>
 93     /// <typeparam name="E3"></typeparam>
 94     public class DbHelper<E1,E2,E3> : DbContext where E1 : class where E2 : class where E3:class
 95     {
 96         public DbHelper(string connectionName = "defaultConnect") : base(connectionName)
 97         {
 98         }
 99 
100         private DbSet<E1> Data1 { get; set; }
101         private DbSet<E2> Data2 { get; set; }
102         private DbSet<E3> Data3 { get; set; }
103         
104     }
105 }

3.使用和操作。

在应用程序初始化的时候(如:Application_Start)执行一次。获取所有要注册的类型。

 1             List<Type> tList = new List<Type>();
 2             var ass = System.Reflection.Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + "\bin\UserApi.dll");
 3 
 4             var uType = ass.GetType("UserApi.User");
 5             var gType = ass.GetType("UserApi.Goods");
 6             var oType = ass.GetType("UserApi.Order");
 7             tList.Add(uType);
 8             tList.Add(gType);
 9             tList.Add(oType);
10 
11             DbHelper.InitDbHelper(tList);

以下是使用语句

//以下操作可能存在于不同的物业模块中
            using(DbHelper<User> db = new DbHelper<UserApi.User>())
            {
                db.Set<User>().Add(new UserApi.User { userId = "zxq", age = 18, userName = "zxq", sex="" });
                db.SaveChanges();
            }
       //联三个表
            using(DbHelper<User, Order, Goods>  db = new DbHelper<UserApi.User, Order, Goods>())
            {
                var u = db.Set<User>();
                var o = db.Set<Order>();
                var g = db.Set<Goods>();

                var q = from uu in u
                        join oo in o
                        on uu.userId equals oo.userId
                        join gg in g
                        on oo.goodsId equals gg.goodsId
                        select new { uu, oo, gg };

                int count = q.Count();
            }
       //联两个表
            using (DbHelper<User,Order> db = new DbHelper<User, Order >())
            {
                db.Set<User>().Add(new UserApi.User
                {
                    userId = "fzj",
                    age = 18,
                    sex = "",
                    userName = "fzj"
                });

                db.Set<Order>().Add(new Order
                {
                    createTime = DateTime.Now,
                    orderId = Guid.NewGuid().ToString("N"),
                    userId = "fzj"
                });

                db.SaveChanges();


                var u = db.Set<User>();
                var o = db.Set<Order>();

                var q = from uu in u
                        join oo in o
                        on uu.userId equals oo.userId
                        select new { uu, oo }; 

                foreach (var item in q)
                {
                    Console.WriteLine("age:{0} orderId:{1}",item.uu.age, item.oo.orderId);
                }

            }

总结:1.以上代码能够解决所有表映射对象必须集中定义的问题,同时解决使用泛型无法联表的问题。

        2.对象(表)的定义使用可以由各业务模块自行控制,只需要按照预先约定好,在注册的时候能够找到该类型即可。

原文地址:https://www.cnblogs.com/LittleJin/p/10582349.html