为了达到模块间最小耦合,单模块业务数据不与其他模块发生关系。在操作数据库的时候,采用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);
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
查看更多关于EF实体对象解耦 - 泛型联表查询的详细内容...