为了达到模块间最小耦合,单模块业务数据不与其他模块发生关系。在操作数据库的时候,采用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定义
//这个对象只是为了注册类型到EF,需要在调用所有数据库语句之前执行一次就够了,具体实现就看设计了。
public class DbHelper : DbContext { public DbHelper() : base("defaultConnect") { } protected override void OnModelCreating(DbModelBuilder modelBuilder) {
//这里通过程序集,实现所有数据库表类型查找。 var ass = System.Reflection.Assembly.LoadFile(AppDomain.CurrentDomain.BaseDirectory + "\\bin\\UserApi.dll"); //根据自己定义的规则,找到所有需要注册的表。 var uType = ass.GetType("UserApi.User"); var gType = ass.GetType("UserApi.Goods"); var oType = ass.GetType("UserApi.Order"); //执行注册。 modelBuilder.RegisterEntityType(uType); modelBuilder.RegisterEntityType(gType); modelBuilder.RegisterEntityType(oType); //modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); base.OnModelCreating(modelBuilder); } }
//定义带一个参数的情况 public class DbHelper<E> : DbContext where E : class { public DbHelper() : base("defaultConnect") { } //用Data调不直观,使用 var u = db.Set<User>();这种形式不易混淆,特别是参数多的情况 internal DbSet<E> Data { get; set; } }
//定义两个表连接情况 public class DbHelper<E1,E2>:DbContext where E1:class where E2:class { public DbHelper() : base("defaultConnect") { } internal DbSet<E1> Data1{ get; set; } internal DbSet<E2> Data2 { get; set; } }
//定义三个表连接情况 public class DbHelper<E1, E2,E3> : DbContext where E1 : class where E2 : class where E3:class { public DbHelper() : base("defaultConnect") { } internal DbSet<E1> Data1 { get; set; } internal DbSet<E2> Data2 { get; set; } internal DbSet<E3> Data3 { get; set; } }
//N个表连接情况。。。。。
3.使用和操作。
//必须执行一次该语句,这个语句只要在调用数据库之前执行一次就够了,具体什么时候执行就看设计者了 using (DbHelper db = new DbHelper()) { try { //实际添加数据不会成功,但在这里将创建所有表。 db.Set<User>().Add(new UserApi.User { }); } catch(Exception ex) { //上面执行肯定会抛出异常 } } //以下操作可能存在于不同的物业模块中 using(DbHelper<User> db = new DbHelper<UserApi.User>()) { db.Set<User>().Add(new UserApi.User { userId = "zxq", age = 31, 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.对象(表)的定义使用可以由各业务模块自行控制,只需要按照预先约定好,在注册的时候能够找到该类型即可。