为了达到模块间最小耦合,单模块业务数据不与其他模块发生关系。在操作数据库的时候,采用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. 关于Spring的一点东西

    Spring IoC 容器 容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁.Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件.这些对象被称为 Spr ...

  2. MySQL的Sleep进程占用大量连接解决方法

    第一部分为产生大量sleep进程的原理及对应解决方法第二部分为设置wait_timeout值,有效减少sleep进程 ========================================= ...

  3. kibana加访问控制时报错--Kibana did not load properly.Check the server output for more information.

    错误 在使用kibana的时候,我们需要对可以进行日志访问进行控制,x-pack插件是最好的选择,但是kibana的x-pack插件是收费的,我们本着节约资源的理念(公司的钱也是钱啊,哈哈),我决定使 ...

  4. 从cpu负载到jstack分析线程状态

    示例代码: public class CPULockTest { private static Object lock1 = new Object(); private static Object l ...

  5. [codeup] 2044 神奇的口袋

    题目描述 有一个神奇的口袋,总的容积是40,用这个口袋可以变出一些物品,这些物品的总体积必须是40.John现在有n个想要得到的物品,每个物品的体积分别是a1,a2--an.John可以从这些物品中选 ...

  6. Echart 改变X轴、Y轴、折线的颜色和数值

    在操作E-chart时需要根据需求改变颜色和属性 图1: option = { xAxis: { type: 'category', data: ['Mon', 'Tue', 'Wed', 'Thu' ...

  7. js如何判断IE浏览器的版本包括IE11

    IE浏览器真是个坑:从ie6以及以前IE版本,简直就是垃圾,不按照Mozilla国际组织的标准来,乱搞.搞得兼容性很差:   <script type="text/javascript ...

  8. WCF使用net.tcp绑定的配置实例

    <system.serviceModel> <bindings> <basicHttpBinding> <!--默认http绑定的配置,这里提高了最大传输信息 ...

  9. Linux学习3-Linux系统安装CentOS6.5

    1.启动虚拟机(虚拟机的安装参见Linux学习1-创建虚拟机) 本此安装系统:CentOS6.5         2.启动客户端后迅速按下F2键进入Bios设置,注意:启动后需鼠标点击虚拟机的屏幕并迅 ...

  10. package.json参数简单介绍

    概述: 每个项目的根目录下都会有一个package.json文件,定义了项目所需的模块,以及项目信息.执行npm install 命令会自动下载package.json中配置的模块,也就是配置项目的运 ...