高性能ORM框架XLinq功能详细介绍
之前简单介绍了XLinq的一些功能,有很多功能都没有提到,现在给XLinq加了一些功能,这次把所有功能都介绍一遍。
设计目标
- 易用性
在使用一个框架的时候
应该没几个人会喜欢写一大堆的配置文件吧
也应该没几个人会喜欢为了完成一个小功能却需要写一大堆代码
这是XLinq开发的首要目标之一,就是尽可能提高易用性
最小配置的情况下仅需要一句连接字符串的配置就可以使用
默认支持的是Sql Server 2008 R2数据库,理论上说也大部分支持了sql server系的其他数据库
- 高性能
目前针对查询时的DataReader转List和批量插入有针对性优化,其他的不太重要的例如批量更新这个并没有太多优化
- 易于调试
出了问题能够以最快速度让使用者定位到问题,其实这些是细节问题
- 支持LINQ
这个其实是跟易用性挂勾的,园子里面有大神写的ORM,声称"无Linq",其实我也不太想用Linq,因为解析Linq实在太难,坑太多,但又找不到另一种比Linq更让我满意的方案。然后我去看了他的ORM的使用方法,发现一旦复杂起来不见得会比Linq更清晰,并且实体类的设计实在是···
Linq实现复杂的语法确实比较蛋疼,sql语句里面直接来几个case when,linq就得写晕过去,至少解析的时候会晕过去。
但在我看来,既然linq语句都比较复杂了,那肯定是有很多的逻辑在里面,就像上面说的case when,那么为什么不把这些逻辑分拆成好几个linq去执行呢?或者干脆点写存储过程里面。
- 多数据库支持
使用方法
- 建立控制台应用程序,暂时只支持.net 4.5.2版本
- 安装xlinq nuget包

- 建立数据库XLinq及相关表

- 添加配置文件
- <connectionStrings>
- <add name="test" connectionString="Data Source=(local);;initial catalog=XLinq;User Id=xinchen;Password=123456"/>
- </connectionStrings>
- 建立TestDataContext类和User实体类
- public class TestDataContext:DataContext
- {
- public TestDataContext():base("test")
- {
- }
- }
- public class User
- {
- public int Id { get; set; }
- public string Username { get; set; }
- }
- 开始使用
- TestDataContext db = new TestDataContext();
- db.Set<User>().ToList();
查询
- 单表查询
Lambda版:
- db.Set<User>().Where(x => x.Username == "xxxx").ToList();
LINQ版:
- (from user in db.Set<User>() where user.Username == "xxxx" select user).ToList();
LINQ版看起来明显感觉比较麻烦,所以在简单查询的时候我更倾向于Lambda表达式
上面的语句生成的代码是一致的
- [Users1].[Id] [Id]
- ,[Users1].[Username] [Username]
- 多表查询
建立实体类的过程不再说
两个表连接查询,因为用Lambda实现比较复杂,所以后面都不再用Lambda实现
- var query = from user in db.Set<User>()
- join userRole in db.Set<UserRole>() on user.Id equals userRole.UserId
- where user.Id == 1 && userRole.RoleId == 1
- select new
- {
- user.Id,
- userRole.RoleId,
- user.Username
- };
生成的语句
五个表连接查询
- var query = from user in db.Set<User>()
- join userRole in db.Set<UserRole>() on user.Id equals userRole.UserId
- join rolePrivilege in db.Set<RolePrivilege>() on userRole.RoleId equals rolePrivilege.RoleId
- join priviege in db.Set<Privilege>() on rolePrivilege.PrivilegeId equals priviege.Id
- join role in db.Set<Role>() on userRole.RoleId equals role.Id
- where user.Id == 1 && userRole.RoleId == 1
- select new
- {
- user.Id,
- userRole.RoleId,
- user.Username,
- PrivilegeName = priviege.Name,
- RoleName = role.Name
- };
生成的语句
- 左连接查询
因为linq本身的左连接写法比较蛋疼,所以xlinq也没有办法,后面会想办法简化
- var query = from user in db.Set<User>()
- join userRole in db.Set<UserRole>() on user.Id equals userRole.UserId into urs
- from ur in urs.DefaultIfEmpty()
- where user.Id == 1 && ur.RoleId == 1
- select new
- {
- user.Id,
- ur.RoleId,
- user.Username
- };
生成的语句
- 延迟加载
- var query = db.Set<User>().Where(x => x.Username == "xxxxx").Select(x => x.Id);
- foreach (var item in query)
- {
- }
- 自连接查询
- var query = from user1 in db.Set<User>()
- join user2 in db.Set<User>() on user1.Id equals user2.Id
- select user1;
生成的语句
- SQL语句查询
- db.SqlQuery<User>("select * from dbo.users", new Dictionary<string, object>());
- 分页查询
- var page = 1;
- var pageSize = 10;
- var query = (from user in db.Set<User>()
- join userRole in db.Set<UserRole>() on user.Id equals userRole.UserId
- join rolePrivilege in db.Set<RolePrivilege>() on userRole.RoleId equals rolePrivilege.RoleId
- join priviege in db.Set<Privilege>() on rolePrivilege.PrivilegeId equals priviege.Id
- join role in db.Set<Role>() on userRole.RoleId equals role.Id
- where user.Id == 1 && userRole.RoleId == 1
- orderby user.Id descending
- select new
- {
- user.Id,
- userRole.RoleId,
- user.Username,
- PrivilegeName = priviege.Name,
- RoleName = role.Name
- }).Skip((page - 1) * pageSize).Take(pageSize);
生成的语句
- 动态查询
- IQueryable<User> query = db.Set<User>();
- var filters = new List<SqlFilter>();
- filters.Add(SqlFilter.Create("Id", Operation.Equal, 1));
- filters.Add(SqlFilter.Create("Username", Operation.Like, "aaa"));
- query = query.Where(filters);
生成的语句
- [Users1].[Id] [Id]
- ,[Users1].[Username] [Username]
- 取日期查询
这个功能主要针对EF中无法直接取日期的问题
- var query = db.Set<User>().Where(x => x.LoginTime.Date == DateTime.Now.Date);
- [Users1].[Id] [Id]
- ,[Users1].[Username] [Username]
- ,[Users1].[LoginTime] [LoginTime]
- 计算天数查询
- var query = db.Set<User>().Where(x => (x.LoginTime - DateTime.Now).TotalDays <= 7);
生成的语句
- [Users1].[Id] [Id]
- ,[Users1].[Username] [Username]
- ,[Users1].[LoginTime] [LoginTime]
修改
- 先查询后修改(注意只有十条数据以内才会支持修改)
- var query = db.Set<User>().FirstOrDefault();
- query.Username = "xxxxxxx";
- db.SaveChanges();
- 直接修改
- db.Set<User>().Where(x => x.Id == 1).Update(x => new User
- {
- Username = "xxxxxxxxxxxxx"
- });
Update子句必须采用这写法才会有效
删除
- 先查询后删除
- var query = db.Set<User>().FirstOrDefault();
- db.Set<User>().Remove(query);
- db.SaveChanges();
- 直接删除
- db.Set<User>().Where(x => x.Id == 1).Delete();
事务
- 普通事务
- using (var scope = new TransactionScope())
- {
- db.Set<User>().Where(x => x.Id == 1).Delete();
- scope.Complete();
- }
- 嵌套事务
- using (var scope = new TransactionScope())
- {
- db.Set<User>().Where(x => x.Id == 1).Delete();
- using (var s1 = new TransactionScope())
- {
- db.Set<Privilege>().Where(x => x.Id == 1).Delete();
- s1.Complete();
- }
- scope.Complete();
- }
调试支持
在调试的时候可直接看到SQL语句


多数据库支持
通过配置文件实现多数据库支持
- <configSections>
- <section name="xlinq" type="Xinchen.XLinq.ConfigSection,Xinchen.XLinq"/>
- </configSections>
- <xlinq connectionStringName="test" dataBase="SQLite"></xlinq>
链式Api
有没有园友注意到,我上面用的User实体并没有进行任何特殊处理,但实际翻译出来的语句是识别的Users表
这其实是"抄"的EF的约定大于配置的原则,默认情况下,实体名的复数就是表名,实体中的Id识别为主键并自动增长
如果需要自定义这些规则,则需要使用特性或链式API,我现在更喜欢链式API
- public class TestDataContext:DataContext
- {
- public TestDataContext():base("test")
- {
- }
- protected override void ConfigurationModel(Xinchen.XLinq.Configuation.EntityConfigurationManager entityConfiguration)
- {
- entityConfiguration.Entity<User>().TableName("Users").Key(x => x.Id, Xinchen.DbUtils.DataAnnotations.DataSourceTypes.AutoIncreament);
- }
- }
重写DataContext的ConfigurationModel方法即可使用链式API对实体相关信息进行配置,上面是指定了User实体的表名、主键及主键的数据来源为自动增长
创建表
若要创建表,则几乎必须使用链式API对实体进行配置之后才能进行自动创建
另外这个功能有一定的限制,默认情况下不会启用该功能,若启用了也只有在数据库中一个表都没有的情况下才会自动创建表
这样做是因为真正的数据库运行环境其实很可能压根不允许自动创建表,然后就是下面这个样子,这样一来这个功能其实并没有太大用,只有在第一次初始化数据库的时候才会用。

当然也可以始终自动创建表,这个需要稍微配置一下,当allwayAutoCreateTables为true时并且autoCreateTables为true时,将始终自动创建表
下面演示创建一个Test表
DataContext中的配置
- public class TestDataContext : DataContext
- {
- public TestDataContext()
- : base("test")
- {
- }
- protected override void ConfigurationModel(Xinchen.XLinq.Configuation.EntityConfigurationManager entityConfiguration)
- {
- var testEntity = entityConfiguration.Entity<Test>().TableName("TestTables").Key(x => x.Id, Xinchen.DbUtils.DataAnnotations.DataSourceTypes.AutoIncreament);
- testEntity.Property(x => x.Id).Name("TId");
- testEntity.Property(x => x.Name).MaxLength(100);
- }
- }
创建的表

自定义Provider(有这功能,但没有测试)
性能
- 查询
- class Program
- {
- static int count = 1;
- static int rowCount = 1000000;
- static void Main(string[] args)
- {
- TestDataContext xlinqDb = new TestDataContext();
- TestDbContext efDb = GetEF(null);
- var userDB = xlinqDb.Set<User>();
- var userRoleDb = xlinqDb.Set<UserRole>();
- var efUserDb = efDb.Users;
- var efUserRoleDb = efDb.UserRoles;
- ExecuteTimer("XLinq使用Linq", () =>
- {
- for (int i = 0; i < count; i++)
- {
- userDB.Take(rowCount).ToList();
- }
- });
- ExecuteTimer("XLinq使用SQL", () =>
- {
- var sql = "select top " + rowCount + " * from dbo.users";
- var dict = new Dictionary<string, object>();
- for (int i = 0; i < count; i++)
- {
- xlinqDb.SqlQuery<User>(sql, dict);
- }
- });
- ExecuteTimer("XLinq多表", () =>
- {
- for (int i = 0; i < count; i++)
- {
- (from user in userDB
- join userRole in userRoleDb on user.Id equals userRole.UserId into us
- from u in us.DefaultIfEmpty()
- select user).Take(rowCount).ToList();
- }
- });
- efDb = GetEF(efDb);
- efUserDb = efDb.Users;
- efUserRoleDb = efDb.UserRoles;
- ExecuteTimer("EF使用LINQ", () =>
- {
- for (int i = 0; i < count; i++)
- {
- efUserDb.Take(rowCount).ToList();
- }
- });
- efDb = GetEF(efDb);
- efUserDb = efDb.Users;
- efUserRoleDb = efDb.UserRoles;
- ExecuteTimer("EF使用SQL", () =>
- {
- var sql = "select top " + rowCount + " * from dbo.users";
- for (int i = 0; i < count; i++)
- {
- efDb.Database.SqlQuery<User>(sql).ToList();
- }
- });
- efDb = GetEF(efDb);
- efUserDb = efDb.Users;
- efUserRoleDb = efDb.UserRoles;
- ExecuteTimer("EF多表", () =>
- {
- for (int i = 0; i < count; i++)
- {
- (from user in efUserDb
- join userRole in efUserRoleDb on user.Id equals userRole.UserId into us
- from u in us.DefaultIfEmpty()
- select user).Take(rowCount).ToList();
- }
- });
- SqlConnection conn = new SqlConnection();
- conn.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings[1].ConnectionString;
- ExecuteTimer("Dapper", () =>
- {
- var sql = "select top " + rowCount + " * from dbo.users";
- for (int i = 0; i < count; i++)
- {
- conn.Query<User>(sql);
- }
- });
- Console.ReadKey();
- }
- static void ExecuteTimer(string name, Action action)
- {
- var watcher = Stopwatch.StartNew();
- action();
- watcher.Stop();
- Console.WriteLine(string.Format("{0}查询{1}数据{2}次", name, rowCount, count).PadRight(30) + ":" + watcher.Elapsed);
- }
- static TestDbContext GetEF(TestDbContext ef)
- {
- if (ef != null)
- {
- ef.Dispose();
- }
- TestDbContext efDb = new TestDbContext();
- efDb.Users.Where(x => false).ToList();
- efDb.Configuration.AutoDetectChangesEnabled = false;
- efDb.Configuration.ProxyCreationEnabled = false;
- efDb.Configuration.ValidateOnSaveEnabled = false;
- return efDb;
- }
- public class TestDbContext : DbContext
- {
- public TestDbContext()
- : base("name=test")
- {
- }
- public System.Data.Entity.DbSet<User> Users { get; set; }
- public System.Data.Entity.DbSet<UserRole> UserRoles { get; set; }
- }
- }
测试结果




查询一次的情况下EF慢的妥妥的,XLinq微弱优势
查询N次的情况下EF这···还有人说EF慢?不过大概是因为缓存的原因,但最后一张图看着又不太像,或许还跟GC什么的关吧,所以还有人说EF慢么··
或者是我测试代码有问题?
- 插入
- class Program
- {
- static int count = 10;
- static int rowCount = 1000;
- static void Main(string[] args)
- {
- TestDataContext xlinqDb = new TestDataContext();
- TestDbContext efDb = GetEF(null);
- var userDB = xlinqDb.Set<User>();
- var userRoleDb = xlinqDb.Set<UserRole>();
- var efUserDb = efDb.Users;
- var efUserRoleDb = efDb.UserRoles;
- ExecuteInsertTimer("XLinq", () =>
- {
- for (int i = 0; i < rowCount; i++)
- {
- userDB.Add(new User()
- {
- C1 = "x",
- C2 = "x",
- C3 = "x",
- C4 = "x",
- C5 = "x",
- C6 = "x",
- C7 = "x",
- C8 = "x",
- C9 = "x",
- C10 = "x",
- Username = "xxxx"
- });
- }
- xlinqDb.SaveChanges();
- });
- ExecuteInsertTimer("EF", () =>
- {
- for (int i = 0; i < rowCount; i++)
- {
- efUserDb.Add(new User()
- {
- C1 = "x",
- C2 = "x",
- C3 = "x",
- C4 = "x",
- C5 = "x",
- C6 = "x",
- C7 = "x",
- C8 = "x",
- C9 = "x",
- C10 = "x",
- Username = "xxxx"
- });
- }
- efDb.SaveChanges();
- });
- Console.ReadKey();
- }
- static void ExecuteTimer(string name, Action action)
- {
- var watcher = Stopwatch.StartNew();
- action();
- watcher.Stop();
- Console.WriteLine(string.Format("{0}查询{1}数据{2}次", name, rowCount, count).PadRight(30) + ":" + watcher.Elapsed);
- }
- static void ExecuteInsertTimer(string name, Action action)
- {
- var watcher = Stopwatch.StartNew();
- action();
- watcher.Stop();
- Console.WriteLine(string.Format("{0}插入{1}条数据", name, rowCount).PadRight(30) + ":" + watcher.Elapsed);
- }
- static TestDbContext GetEF(TestDbContext ef)
- {
- if (ef != null)
- {
- ef.Dispose();
- }
- TestDbContext efDb = new TestDbContext();
- efDb.Users.Where(x => false).ToList();
- efDb.Configuration.AutoDetectChangesEnabled = false;
- efDb.Configuration.ProxyCreationEnabled = false;
- efDb.Configuration.ValidateOnSaveEnabled = false;
- return efDb;
- }
- public class TestDbContext : DbContext
- {
- public TestDbContext()
- : base("name=test")
- {
- }
- public System.Data.Entity.DbSet<User> Users { get; set; }
- public System.Data.Entity.DbSet<UserRole> UserRoles { get; set; }
- }
- }
测试结果




测试源码下载
http://files.cnblogs.com/files/wzxinchen/XlinqDemo.zip
高性能ORM框架XLinq功能详细介绍的更多相关文章
- 高性能ORM 框架之 MySqlSugar
mysql 3.X API地址: http://www.cnblogs.com/sunkaixuan/p/5987308.html MySqlSugar 1.5 API 一.介简 SqlSugar ...
- Java Annotation认知(包括框架图、详细介绍、示例说明)
摘要 Java Annotation是JDK5.0引入的一种注释机制. 网上很多关于Java Annotation的文章,看得人眼花缭乱.Java Annotation本来很简单的,结果说的人没说清楚 ...
- Java Annotation认知(包括框架图、详细介绍、示例说明)(转)
本文转自:http://www.cnblogs.com/skywang12345/p/3344137.html 网上很多关于Java Annotation的文章,看得人眼花缭乱.Java Annota ...
- Ubuntu根目录下各文件夹的功能详细介绍
Ubuntu的根目录下存在着很多的文件夹,但你知道他们都存放着哪些文件呢?这些是深入了解Ubuntu系统必不缺少的知识,本文就关于此做一下介绍吧. /bin/ 用以存储二进制可执行命令文件. / ...
- Asp.Net 高性能ORM框架 SqlSugar.ORM 2.8
3.0最新API: http://www.cnblogs.com/sunkaixuan/p/5911334.html 1.前言/Preface SqlSugar从去年到现在已经一年了,版本从1.0升到 ...
- Asp.Net 高性能ORM框架——SqlSugar
公司团队项目.产品已经完全抛弃EF,SqlSugar定位不是ORM,而是为了方便的让你去写Sql. SqlSugar 媲美原生ADO.NET的性能,语法简洁,并且支持 Json .Dynamic. L ...
- 抓包工具 - HttpWatch(功能详细介绍)
HttpWatch是功能强大的网页数据分析工具,集成在IE工具栏,主要功能有网页摘要.cookies管理.缓存管理.消息头发送/接收,字符查询.POST数据.目录管理功能和报告输出.HttpWatch ...
- HttpWatch功能详细介绍
来源:https://www.cnblogs.com/Chilam007/p/6947235.html HttpWatch是功能强大的网页数据分析工具,集成在IE工具栏,主要功能有网页摘要.cooki ...
- ThinkPHP表单令牌验证功能详细介绍
注:TP版本为3.1.3 在ThinkPHP框架下,两次提交同一个表单,比如提交信息后在浏览器点击后退退回上次的页面,重新点击提交按钮,就会提示“表单令牌错误”的信息. ThinkPHP新版内置了表单 ...
随机推荐
- 3.4 C与汇编程序的相互调用
为了提高代码执行效率,内核源代码中有些地方直接使用了汇编语言编制.这就会涉及在两种语言编制的程序之间相互调用的问题. 函数调用包括从一块代码到另一块代码之间的双向数据传递和执行控制转移.数据传递通过函 ...
- box flex 弹性盒模型(转载)
css3引入了新的盒模型——弹性盒模型,该模型决定一个盒子在其他盒子中的分布方式以及如何处理可用的空间.这与XUL(火狐使用的用户交互语言)相似,其它语言也使用相同的盒模型,如XAML .GladeX ...
- 《javascript权威指南》读书笔记 -part2
我真的很佩服副院长~他是一个很有耐心 极其细致的人 工作态度严谨 代码简洁风格统一~再乱遭遭的代码只要经过他的手就会变的很漂亮 羡煞我也~ 不说废话了 还是乖乖看书吧~maybe可能也许的某一天 ...
- Redis+PHP扩展的安装和Redis集群的配置 与 PHP负载均衡开发方案
以前有想过用 Memcache 实现M/S架构的负载均衡方案,直到听说了 Redis 后才发现它做得更好.发了几天时间研究了一下 Redis ,感觉真的很不错,特整理一下! 以下操作都是在 SUSE ...
- 重定位表 IMAGE_BASE_RELOCATION
typedef struct _IMAGE_BASE_RELOCATION { DWORD VirtualAddress; DWORD SizeOfBlock; // WORD TypeOffset[ ...
- 转:Durandal快速入门
Durandal是一个轻量级的JavaScript框架,其目标是单页面应用(SPAs)的开发变得简单而优雅.它支持MVC.MVP和MVVM等模式,因此不论你采用哪种类型的前端架构,Durandal都能 ...
- CSS5.4 安装问题集
由于手痒,将5.2 卸载了,装了5.4 出现如下错误:install failed to install com.ti.ccstudio.debugserver.win32 corrctly. ... ...
- PHP 之isset() 与 unset()
isset()用来判断某个变量是否已经被声明,他返回一个boolean类型的值,如果声明则返回true否则返回false.如果变量被声明后,给他赋值为NULL,他也返回false. 如: <?p ...
- ViewPager+Fragment的结合使用,实现QQ界面的理解
http://www.cssxt.com/html/2449/2449.html 效果如图: 实现代码解析:MainActivity.java1.引入布局文件2.4个标题控件的初始化以及点击事件的监听 ...
- JVM虚拟机栈和本地方法栈溢出测试
弄JAVA,那JVM,JAVA语法,JDK库,JAVAEE,流行框架是一个都不能少,才可以有全局感的. JVM高级特性这书,看得差不多了.慢慢实践. /** * * *VM Args: -Xms20m ...