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

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

     public class User
{
[Key]
[MaxLength()]
public string userId { get; set; }
[MaxLength()]
public string userName { get; set; }
public int age { get; set; }
public string sex { get; set; }
} public class Order
{
[Key]
[MaxLength()]
public string orderId { get; set; }
public DateTime createTime { get; set; }
public string userId { get; set; } public string goodsId { get; set; }
} public class Goods
{
[Key]
[MaxLength()]
public string goodsId { get; set; }
public decimal price { get; set; }
public float weight { get; set; }
}

2.DbContext定义

     /// <summary>
/// 基础的数据库操作类,
/// 定义了所有的表结构,定义了数据迁移方案
/// </summary>
public class DbHelper : DbContext
{
static List<Type> tList; static DbHelper()
{
//也可以搜索所有程序集里面需要映射表的类型,这样就不需要外部传入了。
} /// <summary>
/// 初始化DB,该方法只需要被调用一次
/// 总的说来,必须要在一开始就知道有哪些类型是要进行表映射的。(准确的说,只要在联表调用之前将对应类型在EF中注册过就可以。使用DbHelper<E>会将新的类型注册到EF,即便这个类型没有在此处统一注册★)
/// </summary>
/// <param name="eTypeList">需要关联的实体类对象</param>
public static void InitDbHelper(List<Type> eTypeList=null)
{
tList = eTypeList ?? tList;
using (DbHelper db = new Db.DbHelper())
{
try
{
db.Set<string>().Add("");
}
catch (InvalidOperationException ex)
{
}
} } public DbHelper() : base("defaultConnect")
{
System.Data.Entity.Database.SetInitializer(new MigrateDatabaseToLatestVersion<DbHelper, Configuration<DbHelper>>());
} public DbHelper(string connectionName= "defaultConnect") : base(connectionName)
{
System.Data.Entity.Database.SetInitializer(new MigrateDatabaseToLatestVersion<DbHelper, Configuration<DbHelper>>());
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
if(tList != null)
{
tList.ForEach(f=>{
modelBuilder.RegisterEntityType(f);
});
}
//modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
base.OnModelCreating(modelBuilder);
}
} /// <summary>
/// 数据迁移设置
/// </summary>
/// <typeparam name="T"></typeparam>
public class Configuration<T> : DbMigrationsConfiguration<T> where T : DbContext
{
public Configuration()
{
AutomaticMigrationsEnabled = true; // 启用自动迁移功能
AutomaticMigrationDataLossAllowed = true; // 允许自动删字段,危险但是不加这个不能重命名字段
}
}
public class DbHelper<E> : DbContext where E : class
{
public DbHelper(string connectionName = "defaultConnect") : base(connectionName)
{
} private DbSet<E> Data { get; set; }
}
public class DbHelper<E1,E2>:DbContext where E1:class where E2:class
{
public DbHelper(string connectionName = "defaultConnect") : base(connectionName)
{
} private DbSet<E1> Data1{ get; set; }
private DbSet<E2> Data2 { get; set; } } /// <summary>
/// 如果超出了这里定义的实体个数,可以由外部自行定义DbHelper。
/// </summary>
/// <typeparam name="E1"></typeparam>
/// <typeparam name="E2"></typeparam>
/// <typeparam name="E3"></typeparam>
public class DbHelper<E1,E2,E3> : DbContext where E1 : class where E2 : class where E3:class
{
public DbHelper(string connectionName = "defaultConnect") : base(connectionName)
{
} private DbSet<E1> Data1 { get; set; }
private DbSet<E2> Data2 { get; set; }
private DbSet<E3> Data3 { get; set; } }
}

3.使用和操作。

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

             List<Type> tList = new List<Type>();
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");
tList.Add(uType);
tList.Add(gType);
tList.Add(oType); 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 = ,
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.对象(表)的定义使用可以由各业务模块自行控制,只需要按照预先约定好,在注册的时候能够找到该类型即可。

EF实体对象解耦 - 泛型联表查询的更多相关文章

  1. MyBatis联表查询

    MyBatis逆向工程主要用于单表操作,那么需要进行联表操作时,往往需要我们自己去写sql语句. 写sql语句之前,我们先修改一下实体类 Course.java: public class Cours ...

  2. Spring Hibernate JPA 联表查询 复杂查询(转)

    今天刷网,才发现: 1)如果想用hibernate注解,是不是一定会用到jpa的? 是.如果hibernate认为jpa的注解够用,就直接用.否则会弄一个自己的出来作为补充. 2)jpa和hibern ...

  3. Spring Hibernate JPA 联表查询 复杂查询

    今天刷网,才发现: 1)如果想用hibernate注解,是不是一定会用到jpa的? 是.如果hibernate认为jpa的注解够用,就直接用.否则会弄一个自己的出来作为补充. 2)jpa和hibern ...

  4. mybatis 联表查询

    一.一对一关联 1.1.提出需求 根据班级id查询班级信息(带老师的信息) 1.2.创建表和数据 创建一张教师表和班级表,这里我们假设一个老师只负责教一个班,那么老师和班级之间的关系就是一种一对一的关 ...

  5. MyBatis-Plus联表查询的短板,终于有一款工具补齐了

    原创:微信公众号 码农参上,欢迎分享,转载请保留出处. 哈喽大家好啊,我是Hydra. mybatis-plus作为mybatis的增强工具,它的出现极大的简化了开发中的数据库操作,但是长久以来,它的 ...

  6. .NET 6 跨服务器联表查询

    一.大家是否有这个需求 1.跨品种查询 :比如 MYSQL和一个SQLSERVER进行联表查询 ,或者SQLITE和MYSQL进行联表查询 2.跨服务器查询 : A服务器和B服务器查询 如果想同时支持 ...

  7. Django之model联表:一对多、跨表操作,联表查询

    表结构概述 model.py : class Something(models.Model): name = models.CharField(max_length=32) class UserTyp ...

  8. FreeSql (十七)联表查询

    FreeSql在查询数据下足了功能,链式查询语法.多表查询.表达式函数支持得非常到位. IFreeSql fsql = new FreeSql.FreeSqlBuilder() .UseConnect ...

  9. Mybatis框架-联表查询显示问题解决

    需求:查询结果要求显示用户名,用户密码,用户的角色 因为在用户表中只有用户角色码值,没有对应的名称,角色名称是在码表smbms_role表中,这时我们就需要联表查询了. 这里需要在User实体类中添加 ...

随机推荐

  1. Picasso加载网络图片失败,提示decodestream时返回null

    最近遇到一个问题,项目用的图片加载框架是Picasso,网络加载框架是okhttp,项目在加载轮播图时有时可以正常加载,有时,会加载失败,提示decodestream时返回null. 首先,需要确定是 ...

  2. Okhttp3上传多张图片同时传递参数

    之前上传图片都是直接将图片转化为io流传给服务器,没有用框架传图片. 最近做项目,打算换个方法上传图片. Android发展到现在,Okhttp显得越来越重要,所以,这次我选择用Okhttp上传图片. ...

  3. Linux -- 使用笔记

    Linux新增分辨率1920x1080 sudo gedit /etc/default/grub 找到:#GRUB_GFXMODE=640x480 在这行下面加一行GRUB_GFXMODE=1920x ...

  4. 数据库学习---SQL基础(二)

    数据库学习---SQL基础(一) 数据库学习---SQL基础(二) 数据库学习---SQL基础(三) 上篇复习的sql的增删改查,and ,or ,>=, <=,!=等逻辑运算符,还有in ...

  5. android学习-Adapter适配器进阶

    参考资源 Android 快速开发系列 打造万能的ListView GridView 适配器 实现代码复用,争取打机**的时间. android4.4源码 target=android-19 一般自定 ...

  6. boost bind使用指南

    bind - boost 头文件: boost/bind.hpp bind 是一组重载的函数模板.用来向一个函数(或函数对象)绑定某些参数. bind的返回值是一个函数对象. 它的源文件太长了. 看不 ...

  7. 从入门到不放弃系列之Koa2

    一.Koa2入门 本来是想Express入门的,但是既然都是要学,干嘛不学最新的呢? 其实我想说,我本来只是想学个小程序开发,现在已经陆陆续续开了好多坑了.. 本文参考廖雪峰教程 二.Async 最新 ...

  8. Cacheable redis 宕机

    使用Cacheable注解Redis方法时,如果Redis服务器挂了,就直接抛出异常了, java.net.ConnectException: Connection refused: connect ...

  9. JavaScript窗口打开与关闭及如何使用opener使子窗口对父窗口进行操作

    一.打开与关闭窗口 1.打开窗口:可以使用window对象中的Open()方法. newWindow = window.open(url,windowname,location); 参数说明: url ...

  10. SQL Server附加数据库拒绝访问解决方法汇总

    @本文来自百度 方法一:修改权限法 1 打开要附加的数据库文件所在的文件夹,即扩展名为mdf的文件所在的文件夹,如下图所示: 2 右键单击mdf文件,选择“属性”,如下图所示: 3 单击“安全”选项卡 ...