【原创】基于.NET的轻量级高性能 ORM - TZM.XFramework
【前言】
接上一篇《【原创】打造基于Dapper的数据访问层》,Dapper在应付多表自由关联、分组查询、匿名查询等应用场景时不免显得吃力,经常要手写SQL语句(或者用工具生成SQL配置文件)。试想一下,项目中整个DAL层都塞满了SQL语句,对于后期维护来说无异于天灾人祸,这个坑谁踩谁知道。本框架在API设计上最大程度地借鉴 EntityFramework 的写法,干净的实体,丝滑的增删改查,稳健的导航属性,另外还支持链式查询(点标记)、查询表达式、聚合查询等等。在实体映射转换层面,使用 Emit 来动态构建绑定指令,性能最大限度地接近原生水平。
【XFramework 亮点】
- 原生.NET语法,零学习成本
- 支持LINQ查询、拉姆达表达式
- 支持批量增删改查和多表关联更新
- 支持 SqlServer、MySql、Postgre、Oracle,.NET Core
- 最大亮点,真正支持一对一、一对多导航属性。这一点相信现有开源的ORM没几个敢说它支持的
- 实体字段类型不必与数据库的类型一致
- 支持临时表、表变量操作
- 提供原生ADO操作
- 其它更多亮点,用了你就会知道
【性能】
看看与EntityFramework的性能对比,机器配置不同跑出来的结果可能也不一样,仅供参考。需要特别说明的是EntityFramework是用了AsNoTracking的,不然有缓存的话就没有比较的意义了。
扯个题外话,有些ORM说比EntityFramework快百分多少多少,看起来挺美实际上在我看来那是在扯淡,没有任何参考价值。限制实体字段类型必须与数据库的一致不说,甚至连导航属性这种最基本的功能都不支持,这不在同一个等级同一个体量上的东西非要扯在一起比谁快,确定要这么幽默吗?本人非常推崇开源,也很尊重致力于开源的同行,但是像这种行为就非常有必要出来打假一波了。
【功能说明】
1. 实体定义
1.1. 如果类有 TableAttribute,则用 TableAttribute 指定的名称做为表名,否则用类名称做为表名
1.2. 实体的字段可以指定 ColumnAttribute 特性来说明实体字段与表字段的对应关系,删除/更新时如果传递的参数是一个实体,必须使用 [Column(IsKey = true)] 指定实体的主键
1.3. ForeignKeyAttribute 指定外键,一对多外键时类型必须是 IList<T> 或者 List<T>
1.4 ColumnAttribute.DataType 用来指定表字段类型。以SQLSERVER为例,System.String 默认对应 nvarchar 类型。若是varchar类型,需要指定[Column(DbType= DbType.AnsiString)]
[Table(Name = "Bas_Client")]
public partial class Client
{
/// <summary>
/// 初始化 <see cref="Client"/> 类的新实例
/// </summary>
public Client()
{
this.CloudServerId = ;
this.Qty = ;
this.HookConstructor();
} /// <summary>
/// 初始化 <see cref="Client"/> 类的新实例
/// </summary>
public Client(Client model)
{
this.CloudServerId = ;
this.Qty = ;
this.HookConstructor();
} /// <summary>
/// clientid
/// </summary>
[Column(IsKey = true)]
public virtual int ClientId { get; set; } /// <summary>
/// clientcode
/// </summary>
public virtual string ClientCode { get; set; } /// <summary>
/// clientname
/// </summary>
public virtual string ClientName { get; set; } /// <summary>
/// cloudserverid
/// </summary>
[Column(Default = )]
public virtual int CloudServerId { get; set; } /// <summary>
/// activedate
/// </summary>
public virtual Nullable<DateTime> ActiveDate { get; set; } /// <summary>
/// qty
/// </summary>
[Column(Default = )]
public virtual int Qty { get; set; } /// <summary>
/// state
/// </summary>
public virtual byte State { get; set; } /// <summary>
/// remark
/// </summary>
[Column(Default = "'默认值'")]
public virtual string Remark { get; set; } [ForeignKey("CloudServerId")]
public virtual CloudServer CloudServer { get; set; } [ForeignKey("CloudServerId")]
public virtual CloudServer LocalServer { get; set; } [ForeignKey("ClientId")]
public virtual List<ClientAccount> Accounts { get; set; } /// <summary>
/// 构造函数勾子
/// </summary>
partial void HookConstructor();
}
2. 上下文定义
SQLSERVER:var context = new SqlDbContext(connString);
MySQL:var context = new MyMySqlDbContext(connString);
Postgre:var context = new NpgDbContext(connString);
Oracle:var context = new OracleDbContext(connString);
3. 匿名类型
//// 匿名类
var guid = Guid.NewGuid();
var dynamicQuery =
from a in context.GetTable<TDemo>()
where a.DemoId <=
select new
{
DemoId = ,
DemoCode = a.DemoCode,
DemoName = a.DemoName,
DemoDateTime_Nullable = a.DemoDateTime_Nullable,
DemoDate = sDate,
DemoDateTime = sDate,
DemoDateTime2 = sDate_null,
DemoGuid = guid,
DemoEnum = Model.State.Complete, // 枚举类型支持
DemoEnum2 = Model.State.Executing,
};
var result0 = dynamicQuery.ToList(); // 点标记
dynamicQuery = context
.GetTable<TDemo>()
.Where(a => a.DemoId <= )
.Select(a => new
{
DemoId = ,
DemoCode = a.DemoCode,
DemoName = a.DemoName,
DemoDateTime_Nullable = a.DemoDateTime_Nullable,
DemoDate = sDate,
DemoDateTime = sDate,
DemoDateTime2 = sDate_null,
DemoGuid = Guid.NewGuid(),
DemoEnum = Model.State.Complete,
DemoEnum2 = Model.State.Executing
});
result0 = dynamicQuery.ToList();
4. 所有字段
// Date,DateTime,DateTime2 支持
var query =
from a in context.GetTable<TDemo>()
where a.DemoId <= && a.DemoDate > sDate && a.DemoDateTime >= sDate && a.DemoDateTime2 > sDate
select a;
var result1 = query.ToList();
// 点标记
query = context
.GetTable<TDemo>()
.Where(a => a.DemoId <= && a.DemoDate > sDate && a.DemoDateTime >= sDate && a.DemoDateTime2 > sDate);
result1 = query.ToList();
5. 指定字段
// 指定字段
query = from a in context.GetTable<TDemo>()
where a.DemoId <=
select new TDemo
{
DemoId = (int)a.DemoId,
DemoCode = (a.DemoCode ?? "N001"),
DemoName = a.DemoId.ToString(),
DemoDateTime_Nullable = a.DemoDateTime_Nullable,
DemoDate = sDate,
DemoDateTime = sDate,
DemoDateTime2 = sDate
};
result1 = query.ToList();
// 点标记
query = context
.GetTable<TDemo>()
.Where(a => a.DemoCode != a.DemoId.ToString() && a.DemoName != a.DemoId.ToString() && a.DemoChar == 'A' && a.DemoNChar == 'B')
.Select(a => new TDemo
{
DemoId = a.DemoId,
DemoCode = a.DemoName == "张三" ? "李四" : "王五",
DemoName = a.DemoCode == "张三" ? "李四" : "王五",
DemoChar = 'A',
DemoNChar = 'B',
DemoDateTime_Nullable = a.DemoDateTime_Nullable,
DemoDate = sDate,
DemoDateTime = sDate,
DemoDateTime2 = sDate
});
result1 = query.ToList();
6.构造函数
用过 EntityFramework 的同学都知道,如果要通过构造函数的方式查询指定字段,除非老老实实重新定义一个新的实体,否则一个 “The entity or complex type cannot be constructed in a LINQ to Entities query“ 的异常马上给甩你脸上。XFramework 框架的这个用法,就是为了让你远离这会呼吸的痛!~
// 构造函数
var query =
from a in context.GetTable<Model.Demo>()
where a.DemoId <=
select new Model.Demo(a);
var r1 = query.ToList();
//SQL=>
//SELECT
//t0.[DemoId] AS [DemoId],
//t0.[DemoCode] AS [DemoCode],
//t0.[DemoName] AS [DemoName],
//...
//FROM [Sys_Demo] t0
//WHERE t0.[DemoId] <= 10
query =
from a in context.GetTable<Model.Demo>()
where a.DemoId <=
select new Model.Demo(a.DemoId, a.DemoName);
r1 = query.ToList();
7. 分页查询
// 分页查询
// 1.不是查询第一页的内容时,必须先OrderBy再分页,OFFSET ... Fetch Next 分页语句要求有 OrderBy
// 2.OrderBy表达式里边的参数必须跟query里边的变量名一致,如此例里的 a。SQL解析时根据此变更生成表别名
query = from a in context.GetTable<TDemo>()
orderby a.DemoCode
select a;
query = query.Skip().Take();
result1 = query.ToList();
// 点标记
query = context
.GetTable<TDemo>()
.OrderBy(a => a.DemoCode)
.Skip()
.Take();
result1 = query.ToList();
8. 过滤条件
// 过滤条件
query = from a in context.GetTable<TDemo>()
where a.DemoName == "D0000002" || a.DemoCode == "D0000002"
select a;
result1 = query.ToList();
// 点标记
query = context.GetTable<TDemo>().Where(a => a.DemoName == "D0000002" || a.DemoCode == "D0000002");
result1 = query.ToList();
query = context.GetTable<TDemo>().Where(a => a.DemoName.Contains(""));
result1 = query.ToList();
query = context.GetTable<TDemo>().Where(a => a.DemoCode.StartsWith("Code000036"));
result1 = query.ToList();
query = context.GetTable<TDemo>().Where(a => a.DemoCode.EndsWith(""));
result1 = query.ToList();
9. 更多条件
// 支持的查询条件
// 区分 nvarchar,varchar,date,datetime,datetime2 字段类型
// 支持的字符串操作=> Trim | TrimStart | TrimEnd | ToString | Length
int m_byte = ;
Model.State state = Model.State.Complete;
query = from a in context.GetTable<TDemo>()
where
a.DemoCode == "" &&
a.DemoName == "" &&
a.DemoCode.Contains("TAN") && // LIKE '%%'
a.DemoName.Contains("TAN") && // LIKE '%%'
a.DemoCode.StartsWith("TAN") && // LIKE 'K%'
a.DemoCode.EndsWith("TAN") && // LIKE '%K'
a.DemoCode.Length == && // LENGTH
a.DemoCode.TrimStart() == "TF" &&
a.DemoCode.TrimEnd() == "TF" &&
a.DemoCode.TrimEnd() == "TF" &&
a.DemoCode.Substring() == "TF" &&
a.DemoDate == DateTime.Now &&
a.DemoDateTime == DateTime.Now &&
a.DemoDateTime2 == DateTime.Now &&
a.DemoName == (
a.DemoDateTime_Nullable == null ? "NULL" : "NOT NULL") && // 三元表达式
a.DemoName == (a.DemoName ?? a.DemoCode) && // 二元表达式
new[] { , , }.Contains(a.DemoId) && // IN(1,2,3)
new List<int> { , , }.Contains(a.DemoId) && // IN(1,2,3)
new List<int>(_demoIdList).Contains(a.DemoId) && // IN(1,2,3)
a.DemoId == new List<int> { , , }[] && // IN(1,2,3)
_demoIdList.Contains(a.DemoId) && // IN(1,2,3)
a.DemoName == _demoName &&
a.DemoCode == (a.DemoCode ?? "CODE") &&
new List<string> { "A", "B", "C" }.Contains(a.DemoCode) &&
a.DemoByte == (byte)m_byte &&
a.DemoByte == (byte)Model.State.Complete ||
a.DemoInt == (int)Model.State.Complete ||
a.DemoInt == (int)state ||
(a.DemoName == "STATE" && a.DemoName == "REMARK")// OR 查询
select a;
result1 = query.ToList();
10. DataTable和DataSet
// DataTable
query = from a in context.GetTable<TDemo>()
orderby a.DemoCode
select a;
query = query.Take();
var result3 = context.Database.ExecuteDataTable(query); // DataSet
var define = query.Resolve();
List<DbCommandDefinition> sqlList = new List<DbCommandDefinition> { define, define, define };
var result4 = context.Database.ExecuteDataSet(sqlList);
11. 内联查询
// INNER JOIN
var query =
from a in context.GetTable<Model.Client>()
join b in context.GetTable<Model.CloudServer>() on a.CloudServerId equals b.CloudServerId
where a.ClientId >
select a;
var result = query.ToList();
// 点标记
query = context
.GetTable<Model.Client>()
.Join(context.GetTable<Model.CloudServer>(), a => a.CloudServerId, b => b.CloudServerId, (a, b) => a)
.Where(a => a.ClientId > );
result = query.ToList();
12. 左联查询
注意看第二个左关联,使用常量作为关联键,翻译出来的SQL语句大概是这样的:
SELECT ***
FROM [Bas_Client] t0
LEFT JOIN [Sys_CloudServer] t1 ON t0.[CloudServerId] = t1.[CloudServerId] AND N'567' = t1.[CloudServerCode]
WHERE t1.[CloudServerName] IS NOT NULL
有没有看到熟悉的味道,兄dei?
// LEFT JOIN
query =
from a in context.GetTable<Model.Client>()
join b in context.GetTable<Model.CloudServer>() on a.CloudServerId equals b.CloudServerId into u_b
from b in u_b.DefaultIfEmpty()
select a;
query = query.Where(a => a.CloudServer.CloudServerName != null);
result = query.ToList(); // LEFT JOIN
query =
from a in context.GetTable<Model.Client>()
join b in context.GetTable<Model.CloudServer>() on new { a.CloudServerId, CloudServerCode = "" } equals new { b.CloudServerId, b.CloudServerCode } into u_b
from b in u_b.DefaultIfEmpty()
select a;
query = query.Where(a => a.CloudServer.CloudServerName != null);
result = query.ToList();
13. 右联查询
左关联和右关联的语法我这里用的是一样的,不过是 DefaultIfEmpty 方法加多了一个重载,DefaultIfEmpty(true) 即表示右关联。
// RIGHT JOIN
query =
from a in context.GetTable<Model.CloudServer>()
join b in context.GetTable<Model.Client>() on a.CloudServerId equals b.CloudServerId into u_b
from b in u_b.DefaultIfEmpty(true)
where a.CloudServerName == null
select b;
result = query.ToList();
14. Union查询
我们的Union查询支持 UNION 操作后再分页哦~
// UNION 注意UNION分页的写法,仅支持写在最后
var q1 = context.GetTable<Model.Client>().Where(x => x.ClientId == );
var q2 = context.GetTable<Model.Client>().Where(x => x.ClientId == );
var q3 = context.GetTable<Model.Client>().Where(x => x.ClientId == );
var query6 = q1.Union(q2).Union(q3);
var result6 = query6.ToList();
result6 = query6.Take().ToList();
result6 = query6.OrderBy(a => a.ClientId).Skip().ToList();
query6 = query6.Take();
result6 = query6.ToList();
query6 = query6.OrderBy(a => a.ClientId).Skip().Take();
result6 = query6.ToList();
15. 导航属性
// 更简单的赋值方式
// 适用场景:在显示列表时只想显示外键表的一两个字段
query =
from a in context.GetTable<Model.Client>()
select new Model.Client(a)
{
CloudServer = a.CloudServer,
LocalServer = new Model.CloudServer
{
CloudServerId = a.CloudServerId,
CloudServerName = a.LocalServer.CloudServerName
}
};
result = query.ToList();
16. 一对一一对多导航
// 1:1关系,1:n关系
query =
from a in context.GetTable<Model.Client>()
where a.ClientId >
orderby a.ClientId
select new Model.Client(a)
{
CloudServer = a.CloudServer,
Accounts = a.Accounts
};
result = query.ToList();
17. Include 语法
EntityFramework 有Include语法,咱也有,而且是实打实的一次性加载!!!
// Include 语法
query =
context
.GetTable<Model.Client>()
.Include(a => a.CloudServer);
--query =
-- from a in query
-- join b in context.GetTable<Model.CloudServer>() on a.CloudServerId equals b.CloudServerId
-- orderby a.ClientId
-- select new Model.Client(a)
-- {
-- CloudServer = a.CloudServer
-- };
result = query.ToList(); // 还是Include,无限主从孙 ###
query =
from a in context
.GetTable<Model.Client>()
.Include(a => a.Accounts)
.Include(a => a.Accounts[].Markets)
.Include(a => a.Accounts[].Markets[].Client)
where a.ClientId >
orderby a.ClientId
select a;
result = query.ToList(); // Include 分页
query =
from a in context
.GetTable<Model.Client>()
.Include(a => a.Accounts)
.Include(a => a.Accounts[].Markets)
.Include(a => a.Accounts[].Markets[].Client)
where a.ClientId >
orderby a.ClientId
select a;
query = query
.Where(a => a.ClientId > && a.CloudServer.CloudServerId > )
.Skip()
.Take();
result = query.ToList();
query =
from a in context
.GetTable<Model.Client>()
.Include(a => a.CloudServer)
.Include(a => a.Accounts)
where a.ClientId >
select a;
query = query.OrderBy(a => a.ClientId);
result = query.ToList(); // Include 语法查询 主 从 孙 关系<注:相同的导航属性不能同时用include和join>
var query1 =
from a in
context
.GetTable<Model.Client>()
.Include(a => a.CloudServer)
.Include(a => a.Accounts)
.Include(a => a.Accounts[].Markets)
.Include(a => a.Accounts[].Markets[].Client)
group a by new { a.ClientId, a.ClientCode, a.ClientName, a.CloudServer.CloudServerId } into g
select new Model.Client
{
ClientId = g.Key.ClientId,
ClientCode = g.Key.ClientCode,
ClientName = g.Key.ClientName,
CloudServerId = g.Key.CloudServerId,
Qty = g.Sum(a => a.Qty)
};
query1 = query1
.Where(a => a.ClientId > )
.OrderBy(a => a.ClientId)
.Skip()
.Take()
;
var result1 = query1.ToList();
18. 分组查询
var query2 =
from a in context.GetTable<Model.Client>()
group a by a.ClientId into g
select new
{
ClientId = g.Key,
Qty = g.Sum(a => a.Qty)
};
query2 = query2.OrderBy(a => a.ClientId).ThenBy(a => a.Qty);
19. 聚合函数
var result1 = query2.Max(a => a.ClientId);
var result2 = query2.Sum(a => a.Qty);
var result3 = query2.Min(a => a.ClientId);
var result4= query2.Average(a => a.Qty);
var result5 = query2.Count();
20. 分组分页
// 分组后再分页
var query8 =
from a in context.GetTable<Model.Client>()
where a.ClientName == "TAN"
group a by new { a.ClientId, a.ClientName } into g
where g.Key.ClientId >
orderby new { g.Key.ClientName, g.Key.ClientId }
select new
{
Id = g.Key.ClientId,
Name = g.Min(a => a.ClientId)
};
query8 = query8.Skip().Take();
var result8 = query8.ToList();
21. 子查询
// 强制转为子查询
query =
from a in context.GetTable<Model.Client>()
join b in context.GetTable<Model.CloudServer>() on a.CloudServerId equals b.CloudServerId into u_c
from b in u_c.DefaultIfEmpty()
select a;
query = query.OrderBy(a => a.ClientId).Skip().Take().AsSubQuery();
query = from a in query
join b in context.GetTable<Model.Client>() on a.ClientId equals b.ClientId
select a;
result = query.ToList();
22. Any 查询
// Any
var isAny = context.GetTable<Model.Client>().Any();
isAny = context.GetTable<Model.Client>().Any(a => a.ActiveDate == DateTime.Now);
isAny = context.GetTable<Model.Client>().Distinct().Any(a => a.ActiveDate == DateTime.Now);
isAny = context.GetTable<Model.Client>().OrderBy(a => a.ClientId).Skip().Take().Any(a => a.ActiveDate == DateTime.Now);
//SQL=>
//IF EXISTS(
// SELECT TOP 1 1
// FROM[Bas_Client] t0
// WHERE t0.[ActiveDate] = '2018-08-15 14:07:09.784'
//) SELECT 1 ELSE SELECT 0
23. 单个删除
// 1. 删除单个记录
var demo = new TDemo { DemoId = };
context.Delete(demo);
context.SubmitChanges();
24. 批量删除
// 2.WHERE 条件批量删除
context.Delete<TDemo>(a => a.DemoId == || a.DemoId == || a.DemoName == "N0000004");
var qeury =
context
.GetTable<TDemo>()
.Where(a => a.DemoId == || a.DemoId == || a.DemoName == "N0000004");
// 2.WHERE 条件批量删除
context.Delete<TDemo>(qeury);
context.SubmitChanges();
25. 多表关联删除
// 3.Query 关联批量删除
var query1 =
from a in context.GetTable<Model.Client>()
join b in context.GetTable<Model.ClientAccount>() on a.ClientId equals b.ClientId
join c in context.GetTable<Model.ClientAccountMarket>() on new { b.ClientId, b.AccountId } equals new { c.ClientId, c.AccountId }
where c.ClientId == && c.AccountId == "" && c.MarketId ==
select a;
context.Delete<Model.Client>(query1); // oracle 不支持导航属性关联删除
// 3.Query 关联批量删除
var query2 =
from a in context.GetTable<Model.Client>()
join b in context.GetTable<Model.ClientAccount>() on a.ClientId equals b.ClientId
where a.CloudServer.CloudServerId == && a.LocalServer.CloudServerId ==
select a;
context.Delete<Model.Client>(query2);
// 4.Query 关联批量删除
var query3 =
from a in context.GetTable<Model.Client>()
where a.CloudServer.CloudServerId == && a.LocalServer.CloudServerId ==
select a;
context.Delete<Model.Client>(query3); // 5.子查询批量删除
// 子查询更新
var sum =
from a in context.GetTable<Model.ClientAccount>()
where a.ClientId <=
group a by new { a.ClientId } into g
select new Model.Client
{
ClientId = g.Key.ClientId,
Qty = g.Sum(a => a.Qty)
};
var query4 =
from a in context.GetTable<Model.Client>()
join b in context.GetTable<Model.CloudServer>() on a.CloudServerId equals b.CloudServerId
join c in context.GetTable<Model.CloudServer>() on a.CloudServerId equals c.CloudServerId
join d in sum on a.ClientId equals d.ClientId
where a.ClientId > && a.CloudServerId <
select a;
context.Delete<Model.Client>(query4);
26. 单个更新
var demo = context
.GetTable<TDemo>()
.FirstOrDefault(x => x.DemoId > ); // 整个实体更新
demo.DemoName = "001'.N";
context.Update(demo);
context.SubmitChanges();
27.批量更新
// 2.WHERE 条件批量更新
context.Update<TDemo>(x => new TDemo
{
DemoDateTime2 = DateTime.UtcNow,
DemoDateTime2_Nullable = null,
//DemoTime_Nullable = ts
}, x => x.DemoName == "001'.N" || x.DemoCode == "001'.N");
context.SubmitChanges();
28. 多表关联更新
这里还支持将B表字段的值更新回A表,有多方便你自己体会。事先声明,Oracle和Postgre是不支持这种sao操作的。
// 3.Query 关联批量更新
var query =
from a in context.GetTable<Model.Client>()
where a.CloudServer.CloudServerId !=
select a;
context.Update<Model.Client>(a => new Model.Client
{
Remark = "001.TAN"
}, query); // 更新本表值等于从表的字段值
query =
from a in context.GetTable<Model.Client>()
join b in context.GetTable<Model.CloudServer>() on a.CloudServerId equals b.CloudServerId
join c in context.GetTable<Model.ClientAccount>() on a.ClientId equals c.ClientId
where c.AccountId == ""
select a;
context.Update<Model.Client, Model.CloudServer>((a, b) => new Model.Client
{
CloudServerId = b.CloudServerId,
Remark = "001.TAN"
}, query);
context.SubmitChanges();
29. 子查询更新
// 子查询更新
var sum =
from a in context.GetTable<Model.ClientAccount>()
where a.ClientId >
group a by new { a.ClientId } into g
select new Model.Client
{
ClientId = g.Key.ClientId,
Qty = g.Sum(a => a.Qty)
};
if (_databaseType == DatabaseType.SqlServer || _databaseType == DatabaseType.MySql)
{
var uQuery =
from a in context.GetTable<Model.Client>()
join b in sum on a.ClientId equals b.ClientId
where a.ClientId > && b.ClientId >
select a;
context.Update<Model.Client, Model.Client>((a, b) => new Model.Client { Qty = b.Qty }, uQuery);
}
else
{
// npg oracle 翻译成 EXISTS,更新字段的值不支持来自子查询
var uQuery =
from a in context.GetTable<Model.Client>()
join b in sum on a.ClientId equals b.ClientId
where a.ClientId > // b.ClientId > 0
select a;
context.Update<Model.Client>(a => new Model.Client { Qty = }, uQuery);
}
context.SubmitChanges();
30. 带自增列新增
// 带自增列
var demo = new TDemo
{
DemoCode = "D0000001",
DemoName = "N0000001",
DemoBoolean = true,
DemoChar = 'A',
DemoNChar = 'B',
DemoByte = ,
DemoDate = DateTime.Now,
DemoDateTime = DateTime.Now,
DemoDateTime2 = DateTime.Now,
DemoDecimal = ,
DemoDouble = ,
DemoFloat = ,
DemoGuid = Guid.NewGuid(),
DemoShort = ,
DemoInt = ,
DemoLong =
};
context.Insert(demo);
context.SubmitChanges(); var demo2 = new TDemo
{
DemoCode = "D0000002",
DemoName = "N0000002",
DemoBoolean = true,
DemoChar = 'A',
DemoNChar = 'B',
DemoByte = ,
DemoDate = DateTime.Now,
DemoDateTime = DateTime.Now,
DemoDateTime2 = DateTime.Now,
DemoDecimal = ,
DemoDouble = ,
DemoFloat = ,
DemoGuid = Guid.NewGuid(),
DemoShort = ,
DemoInt = ,
DemoLong =
};
context.Insert(demo2); var demo3 = new TDemo
{
DemoCode = "D0000003",
DemoName = "N0000003",
DemoBoolean = true,
DemoChar = 'A',
DemoNChar = 'B',
DemoByte = ,
DemoDate = DateTime.Now,
DemoDateTime = DateTime.Now,
DemoDateTime2 = DateTime.Now,
DemoDecimal = ,
DemoDouble = ,
DemoFloat = ,
DemoGuid = Guid.NewGuid(),
DemoShort = ,
DemoInt = ,
DemoLong =
};
context.Insert(demo3);
context.Insert(demo);
context.SubmitChanges();
31. 批量新增
批量新增翻译的SQL不带参数,只是纯SQL文本。SQLSERVER的同学如果想更快,可以尝尝 SqlDbContext.BulkCopy方法。
// 批量增加
// 产生 INSERT INTO VALUES(),(),()... 语法。注意这种批量增加的方法并不能给自增列自动赋值
context.Delete<TDemo>(x => x.DemoId > );
demos = new List<TDemo>();
for (int i = ; i < ; i++)
{
TDemo d = new TDemo
{
DemoCode = "D0000001",
DemoName = "N0000001",
DemoBoolean = true,
DemoChar = 'A',
DemoNChar = 'B',
DemoByte = ,
DemoDate = DateTime.Now,
DemoDateTime = DateTime.Now,
DemoDateTime2 = DateTime.Now,
DemoDecimal = ,
DemoDouble = ,
DemoFloat = ,
DemoGuid = Guid.NewGuid(),
DemoShort = ,
DemoInt = ,
DemoLong =
};
demos.Add(d);
}
context.Insert<TDemo>(demos);
context.SubmitChanges();
32. 关联查询新增
// 子查询增
var sum =
from a in context.GetTable<Model.ClientAccount>()
where a.ClientId >
group a by new { a.ClientId } into g
select new Model.Client
{
ClientId = g.Key.ClientId,
Qty = g.Sum(a => a.Qty)
};
sum = sum.AsSubQuery(); maxId = context.GetTable<Model.Client>().Max(x => x.ClientId);
nextId = maxId + ;
var nQuery =
from a in sum
join b in context.GetTable<Model.Client>() on a.ClientId equals b.ClientId into u_b
from b in u_b.DefaultIfEmpty()
where b.ClientId == null
select new Model.Client
{
ClientId = SqlMethod.RowNumber<int>(x => a.ClientId) + nextId,
ClientCode = "ABC3",
ClientName = "啊啵呲3",
CloudServerId = ,
State = ,
Qty = a.Qty,
};
context.Insert(nQuery);
33. 增删改同时查出数据
context.Update<Model.Client>(x => new Model.Client
{
ClientName = "蒙3"
}, x => x.ClientId == );
var query =
from a in context.GetTable<Model.Client>()
where a.ClientId ==
select ;
context.AddQuery(query);
List<int> result1 = null;
context.SubmitChanges(out result1); context.Update<Model.Client>(x => new Model.Client
{
ClientName = "蒙4"
}, x => x.ClientId == );
query =
from a in context.GetTable<Model.Client>()
where a.ClientId ==
select ;
context.AddQuery(query);
var query2 =
from a in context.GetTable<Model.Client>()
where a.ClientId ==
select ;
context.AddQuery(query2);
result1 = null;
List<int> result2 = null;
context.SubmitChanges(out result1, out result2);
34. 一次性加载多个列表
// 一性加载多个列表 ****
var query3 =
from a in context.GetTable<Model.Client>()
where a.ClientId >= && a.ClientId <=
select ;
var query4 =
from a in context.GetTable<Model.Client>()
where a.ClientId >= && a.ClientId <=
select ;
var tuple = context.Database.ExecuteMultiple<int, int>(query3, query4); query3 =
from a in context.GetTable<Model.Client>()
where a.ClientId >= && a.ClientId <=
select ;
query4 =
from a in context.GetTable<Model.Client>()
where a.ClientId >= && a.ClientId <=
select ;
var query5 =
from a in context.GetTable<Model.Client>()
where a.ClientId >= && a.ClientId <=
select ;
var tuple2 = context.Database.ExecuteMultiple<int, int, int>(query3, query4, query5);
35. 事务操作
借鉴 EntityFramework的思想,本框架也支持自身开启事务,或者从其它上下文开启事务后再在本框架使用该事务。
// 事务1. 上下文独立事务
try
{
using (var transaction = context.Database.BeginTransaction())
{
var result = context.GetTable<Model.Client>().FirstOrDefault(x => x.ClientId <= );
context.Update<Model.Client>(x => new Model.Client
{
ClientName = "事务1"
}, x => x.ClientId == result.ClientId);
context.SubmitChanges();
result = context.GetTable<Model.Client>().FirstOrDefault(x => x.ClientId == result.ClientId); context.Update<Model.Client>(x => new Model.Client
{
ClientName = "事务2"
}, x => x.ClientId == result.ClientId);
context.SubmitChanges();
result = context.GetTable<Model.Client>().FirstOrDefault(x => x.ClientId == result.ClientId); //throw new Exception("假装异常");
//transaction.Rollback();
transaction.Commit();
}
}
finally
{
// 开启事务后必需显式释放资源
context.Dispose();
} // 事务2. 使用其它的事务
IDbTransaction transaction2 = null;
IDbConnection connection = null;
try
{
connection = context.Database.DbProviderFactory.CreateConnection();
connection.ConnectionString = context.Database.ConnectionString;
if (connection.State != ConnectionState.Open) connection.Open();
transaction2 = connection.BeginTransaction(); // 指定事务
context.Database.Transaction = transaction2; var result = context.GetTable<Model.Client>().FirstOrDefault(x => x.ClientId <= );
context.Update<Model.Client>(x => new Model.Client
{
ClientName = "事务3"
}, x => x.ClientId == result.ClientId);
context.SubmitChanges();
result = context.GetTable<Model.Client>().FirstOrDefault(x => x.ClientId == result.ClientId); context.Update<Model.Client>(x => new Model.Client
{
ClientName = "事务4"
}, x => x.ClientId == result.ClientId);
result = context.GetTable<Model.Client>().FirstOrDefault(x => x.ClientId == result.ClientId); string sql = @"UPDATE Bas_Client SET ClientName = N'事务5' WHERE ClientID=2;UPDATE Bas_Client SET ClientName = N'事务6' WHERE ClientID=3;";
context.AddQuery(sql);
context.SubmitChanges(); transaction2.Commit();
}
catch
{
if (transaction2 != null) transaction2.Rollback();
throw;
}
finally
{
if (transaction2 != null) transaction2.Dispose();
if (connection != null) connection.Close();
if (connection != null) connection.Dispose(); context.Dispose();
}
36. 表变量
SQLSERVER的童鞋看过来,你要的爽本框架都能给~
// 声明表变量
var typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo<SqlServerModel.JoinKey>();
context.AddQuery(string.Format("DECLARE {0} [{1}]", typeRuntime.TableName, typeRuntime.TableName.TrimStart('@')));
List<SqlServerModel.JoinKey> keys = new List<SqlServerModel.JoinKey>
{
new SqlServerModel.JoinKey{ Key1 = },
new SqlServerModel.JoinKey{ Key1 = },
};
// 向表变量写入数据
context.Insert<SqlServerModel.JoinKey>(keys);
// 像物理表一样操作表变量
var query =
from a in context.GetTable<Model.Client>()
join b in context.GetTable<SqlServerModel.JoinKey>() on a.ClientId equals b.Key1
select a;
context.AddQuery(query);
// 提交查询结果
List<Model.Client> result = null;
context.SubmitChanges(out result);
【结语】
XFramework 已成熟运用于我们公司的多个核心项目,完全代替了之前的 Dapper + DbHelper的数据持久方案。从最初只支持SQLSERVER到支持MySQL、Postgre和Oracle,一个多月的熬夜坚持,个中酸爽只有经历过才能体会。你的喜爱和支持是我在开源的路上一路狂奔的最大动力,撸码不易,不喜请轻喷。但我相信,这绝对是一款人性化、有温度的数据持久框架!!!
XFramework 现已完全开源,遵循 Apache2.0 协议,托管地址:
码云:https://gitee.com/TANZAME/TZM.XFramework
GitHub:https://github.com/TANZAME/TZM.XFramework
ORM 技术交流群:816425449
【原创】基于.NET的轻量级高性能 ORM - TZM.XFramework的更多相关文章
- 【原创】基于.NET的轻量级高性能 ORM - TZM.XFramework 之优雅增删改
[前言] 大家好,我是TANZAME.出乎意料的,我们在立冬的前一天又见面了,天气慢慢转凉,朋友们注意添衣保暖,愉快撸码.距离 TZM.XFramework 的首秀已数月有余,期间收到不少朋友的鼓励. ...
- 【原创】基于.NET的轻量级高性能 ORM - TZM.XFramework 之让代码更优雅
[前言] 大家好,我是TANZAME.出乎意料的,我们在立冬的前一天又见面了,天气慢慢转凉,朋友们注意添衣保暖,愉快撸码.距离 TZM.XFramework 的首秀已数月有余,期间收到不少朋友的鼓励. ...
- 轻量级高性能ORM框架:Dapper高级玩法
Dapper高级玩法1: 数据库中带下划线的表字段自动匹配无下划线的Model字段. Dapper.DefaultTypeMap.MatchNamesWithUnderscores = true; 备 ...
- PetaPoco - 轻量级高性能的ORM框架(支持.NET Core)
我们都知道ORM全称叫做Object Relationship Mapper,也就是可以用object来map我们的db. 而且市面上的orm框架有很多,有重量级的Entity Framework,有 ...
- 轻量级.NET ORM、高性能.NET ORM 之 SqlSugar 开源ORM - ASP.NET
3.0最新API: http://www.cnblogs.com/sunkaixuan/p/5911334.html 1.前言/Preface SqlSugar从去年到现在已经一年了,版本从1.0升到 ...
- 分享自己写的基于Dapper的轻量级ORM框架~
1.说明 本项目是一个使用.NET Standard 2.0开发的,基于 Dapper 的轻量级 ORM 框架,包含基本的CRUD以及根据表达式进行一些操作的方法,目前只针对单表,不包含多表连接操作. ...
- Android高性能ORM数据库DBFlow入门
DBFlow,综合了 ActiveAndroid, Schematic, Ollie,Sprinkles 等库的优点.同时不是基于反射,所以性能也是非常高,效率紧跟greenDAO其后.基于注解,使用 ...
- 基于nginx+lua+redis高性能api应用实践
基于nginx+lua+redis高性能api应用实践 前言 比较传统的服务端程序(PHP.FAST CGI等),大多都是通过每产生一个请求,都会有一个进程与之相对应,请求处理完毕后相关进程自动释放. ...
- FluentData - 轻量级.NET ORM持久化技术解决方式
FluentData - 轻量级.NET ORM持久化技术解决方式 文件夹: 一.什么是ORM? 二.使用ORM的优势 三.使用ORM的缺点 四.NET下的ORM框架有哪些? 五.几 ...
随机推荐
- 小程序红包开发跳坑记 微信小程序红包接口开发过程中遇到的问题 微信小程序红包开发
现在做小程序的越来越多,商家推广也是一个瓶颈,谁不发点红包,都很难找到人来用你的微信小程序了.于是不管你开发什么小程序功能,你或多或少都要用到小程序来发红包吧. 我们自己之前做公众号发红包,做了两三 ...
- The OAuth 2.0 Authorization Framework
The OAuth 2.0 Authorization Framework Abstract The OAuth 2.0 authorization framework enables a thi ...
- mysql 各种级联查询后更新(update select).
mysql 各种级联查询后更新(update select). CREATE TABLE `tb1` ( `id` int(11) NOT NULL, `A` varchar(100) de ...
- .net3.5下使用LINQ递归算法实现简洁代码
原文发布时间为:2011-04-24 -- 来源于本人的百度文章 [由搬家工具导入] http://www.cnblogs.com/wintersun/archive/2009/03/29/14243 ...
- Berkeley DB Java Edition 简介
一. 简介 Berkeley DB Java Edition (JE)是一个完全用JAVA写的,它适合于管理海量的,简单的数据. l 能够高效率的 ...
- OpenGL入门学习(二)
http://developer.178.com/201103/94954661733.html 一.点.直线和多边形我们知道数学(具体的说,是几何学)中有点.直线和多边形的概念,但这些概念在计算机中 ...
- 教学生jni编程(一)
我的所有文件的目录在/home/michelle/WORKM/DAYCODE/day0426/,请根据个人情况适当调整 1)创建一个HelloWorld.Java文件,如下: public class ...
- 移动开发平台 apicloud、wex5
http://www.apicloud.com/deepengine http://www.wex5.com
- LeetCode OJ-- LRU Cache ***@
https://oj.leetcode.com/problems/lru-cache/ 涨姿势的一道题,相当于实现一种数据结构,实现最近最少使用数据结构. // 用来记录 前后节点都是什么 类似链表上 ...
- Codeforces Round #467 (Div. 2) A. Olympiad[输入一组数,求该数列合法的子集个数]
A. Olympiad time limit per test 1 second memory limit per test 256 megabytes input standard input ou ...