扯淡

13年毕业之际,进入第一家公司实习,接触了 EntityFramework,当时就觉得这东西太牛了,访问数据库都可以做得这么轻松、优雅!毕竟那时还年轻,没见过世面。工作之前为了拿个实习机会混个工作证明,匆匆忙忙学了两个月的 C#,就这样,稀里糊涂的做了程序员,从此走上了一条不归路。那会也只知道 SqlHelper,DataTable。ORM?太高大上,没听说过。虽然在第一家公司只呆了两个月,但让我认识了 EntityFramework,从此也走上了 ORM 的不归路...纯纯的实体,增改删超级简单,查询如行云流水,真心没理由抗拒!以至于后来进入第二家公司做开发极其不适应,因为他们没用 EF,也不用类 linq 的 ORM,他们有自己数据库访问框架。那套东西实体设计复杂,支持的功能少,查询条件还依赖字符串,开发容错率太低,DB操作入口接口设计也很重,里面方法不下60个,看心凉,用心累!那时,好怀念 EF~在新公司工作的时间内,来回都是增改页面,做增删查改,修复BUG,多少有点枯燥乏味,渐渐感觉编码能力提升太慢。同时鉴于用公司的 ORM 也不是很顺手,于是,萌生了自己写 ORM 的念头,再然后...Chloe.ORM 面世了~

导航

Chloe.ORM

Chloe 查询接口设计借(zhao)鉴(ban) linq,但不支持 linq。开发之前,我给我的 ORM 查询条件接口定义一定要支持lambda表达式(潮流、趋势,在这不讨论表达式树的性能)。开发之初,也有自己设计过查询接口,想了一套又一套,始终没 linq 设计的接口方便,后来,不想了,直接抄 linq,不解释!前人如此伟大设计,不用真对不起他们,我要站在他们的肩膀上!

先看下 IDbContext 接口:

  1. public interface IDbContext : IDisposable
  2. {
  3. IDbSession CurrentSession { get; }
  4.  
  5. IQuery<T> Query<T>() where T : new();
  6. IEnumerable<T> SqlQuery<T>(string sql, params DbParam[] parameters) where T : new();
  7.  
  8. T Insert<T>(T entity);
  9. object Insert<T>(Expression<Func<T>> body);
  10.  
  11. int Update<T>(T entity);
  12. int Update<T>(Expression<Func<T, T>> body, Expression<Func<T, bool>> condition);
  13.  
  14. int Delete<T>(T entity);
  15. int Delete<T>(Expression<Func<T, bool>> condition);
  16.  
  17. void TrackEntity(object entity);
  18. }

Chloe 操作入口是 IDbContext。IDbContext 仅有两个 Query、两个 Insert、两个 Update 、两个 Delete 和一个 TrackEntity 方法,以及一个 CurrentSession 的属性,设计很简单,但绝对能满足81%的需求(多一点满足,多一分热爱)!
这篇文章,主要介绍 Query 接口使用。

事前准备

实体:

  1. public enum Gender
  2. {
  3. Man = 1,
  4. Woman
  5. }
  6.  
  7. [TableAttribute("Users")]
  8. public class User
  9. {
  10. [Column(IsPrimaryKey = true)]
  11. [AutoIncrementAttribute]
  12. public int Id { get; set; }
  13. public string Name { get; set; }
  14. public Gender? Gender { get; set; }
  15. public int? Age { get; set; }
  16. public int? CityId { get; set; }
  17. public DateTime? OpTime { get; set; }
  18. }
  19.  
  20. public class City
  21. {
  22. [Column(IsPrimaryKey = true)]
  23. public int Id { get; set; }
  24. public string Name { get; set; }
  25. public int ProvinceId { get; set; }
  26. }
  27.  
  28. public class Province
  29. {
  30. [Column(IsPrimaryKey = true)]
  31. public int Id { get; set; }
  32. public string Name { get; set; }
  33. }

首先,创建一个 DbContext:

  1. IDbContext context = new MsSqlContext(DbHelper.ConnectionString);

再创建一个 IQuery<T>:

  1. IQuery<User> q = context.Query<User>();

基本查询

  1. IQuery<User> q = context.Query<User>();
  2. q.Where(a => a.Id > 0).FirstOrDefault();
  3. q.Where(a => a.Id > 0).ToList();
  4. q.Where(a => a.Id > 0).OrderBy(a => a.Age).ToList();
  5. q.Where(a => a.Id > 0).Take(999).OrderBy(a => a.Age).ToList();
  6.  
  7. //分页。避免生成的 sql 语句太长占篇幅,只选取 Id 和 Name 两个字段
  8. q.Where(a => a.Id > 0).OrderBy(a => a.Age).ThenByDesc(a => a.Id).Select(a => new { a.Id, a.Name }).Skip(1).Take(999).ToList();
  9. /*
  10. * SELECT TOP (999) [T].[Id] AS [Id],[T].[Name] AS [Name] FROM (SELECT [Users].[Id] AS [Id],[Users].[Name] AS [Name],ROW_NUMBER() OVER(ORDER BY [Users].[Age] ASC,[Users].[Id] DESC) AS [ROW_NUMBER_0] FROM [Users] AS [Users] WHERE [Users].[Id] > 0) AS [T] WHERE [T].[ROW_NUMBER_0] > 1
  11. */
  12.  
  13. //如果需要多个条件的话
  14. q.Where(a => a.Id > 0).Where(a => a.Name.Contains("lu")).ToList();
  15. /*
  16. * SELECT [Users].[Id] AS [Id],[Users].[Name] AS [Name],[Users].[Gender] AS [Gender],[Users].[Age] AS [Age],[Users].[CityId] AS [CityId],[Users].[OpTime] AS [OpTime] FROM [Users] AS [Users] WHERE ([Users].[Id] > 0 AND [Users].[Name] LIKE '%' + N'lu' + '%')
  17. */
  18.  
  19. //选取指定字段
  20. q.Select(a => new { a.Id, a.Name, a.Age }).ToList();
  21. //或者
  22. q.Select(a => new User() { Id = a.Id, Name = a.Name, Age = a.Age }).ToList();
  23. /*
  24. * SELECT [Users].[Id] AS [Id],[Users].[Name] AS [Name],[Users].[Age] AS [Age] FROM [Users] AS [Users]
  25. */

连接查询

建立连接:

  1. MsSqlContext context = new MsSqlContext(DbHelper.ConnectionString);
  2. IQuery<User> users = context.Query<User>();
  3. IQuery<City> cities = context.Query<City>();
  4. IQuery<Province> provinces = context.Query<Province>();
  5.  
  6. IJoiningQuery<User, City> user_city = users.InnerJoin(cities, (user, city) => user.CityId == city.Id);
  7. IJoiningQuery<User, City, Province> user_city_province = user_city.InnerJoin(provinces, (user, city, province) => city.ProvinceId == province.Id);

只获取 UserId,CityName,ProvinceName:

  1. user_city_province.Select((user, city, province) => new { UserId = user.Id, CityName = city.Name, ProvinceName = province.Name }).Where(a => a.UserId == 1).ToList();
  2. /*
  3. * SELECT [Users].[Id] AS [UserId],[City].[Name] AS [CityName],[Province].[Name] AS [ProvinceName] FROM [Users] AS [Users] INNER JOIN [City] AS [City] ON [Users].[CityId] = [City].[Id] INNER JOIN [Province] AS [Province] ON [City].[ProvinceId] = [Province].[Id] WHERE [Users].[Id] = 1
  4. */

调用 Select 方法返回一个包含所有信息的 IQuery<T> 对象:

  1. var view = user_city_province.Select((user, city, province) => new { User = user, City = city, Province = province });

查出一个用户及其隶属的城市和省份:

  1. view.Where(a => a.User.Id == 1).ToList();
  2. /*
  3. * SELECT [Users].[Id] AS [Id],[Users].[Name] AS [Name],[Users].[Gender] AS [Gender],[Users].[Age] AS [Age],[Users].[CityId] AS [CityId],[Users].[OpTime] AS [OpTime],[City].[Id] AS [Id0],[City].[Name] AS [Name0],[City].[ProvinceId] AS [ProvinceId],[Province].[Id] AS [Id1],[Province].[Name] AS [Name1] FROM [Users] AS [Users] INNER JOIN [City] AS [City] ON [Users].[CityId] = [City].[Id] INNER JOIN [Province] AS [Province] ON [City].[ProvinceId] = [Province].[Id] WHERE [Users].[Id] = 1
  4. */

这时候也可以选取指定的字段:

  1. view.Where(a => a.User.Id == 1).Select(a => new { UserId = a.User.Id, CityName = a.City.Name, ProvinceName = a.Province.Name }).ToList();
  2. /*
  3. * SELECT [Users].[Id] AS [UserId],[City].[Name] AS [CityName],[Province].[Name] AS [ProvinceName] FROM [Users] AS [Users] INNER JOIN [City] AS [City] ON [Users].[CityId] = [City].[Id] INNER JOIN [Province] AS [Province] ON [City].[ProvinceId] = [Province].[Id] WHERE [Users].[Id] = 1
  4. */

Chloe 也支持 Left Join、Right Join、Full Join 连接,用法和 Inner Join 一样,就不一一介绍了。

聚合函数

  1. IQuery<User> q = context.Query<User>();
  2.  
  3. q.Select(a => DbFunctions.Count()).First();
  4. /*
  5. * SELECT TOP (1) COUNT(1) AS [C] FROM [Users] AS [Users]
  6. */
  7.  
  8. q.Select(a => new { Count = DbFunctions.Count(), LongCount = DbFunctions.LongCount(), Sum = DbFunctions.Sum(a.Age), Max = DbFunctions.Max(a.Age), Min = DbFunctions.Min(a.Age), Average = DbFunctions.Average(a.Age) }).First();
  9. /*
  10. * SELECT TOP (1) COUNT(1) AS [Count],COUNT_BIG(1) AS [LongCount],SUM([Users].[Age]) AS [Sum],MAX([Users].[Age]) AS [Max],MIN([Users].[Age]) AS [Min],CAST(AVG([Users].[Age]) AS FLOAT) AS [Average] FROM [Users] AS [Users]
  11. */
  12.  
  13. var count = q.Count();
  14. /*
  15. * SELECT COUNT(1) AS [C] FROM [Users] AS [Users]
  16. */
  17.  
  18. var longCount = q.LongCount();
  19. /*
  20. * SELECT COUNT_BIG(1) AS [C] FROM [Users] AS [Users]
  21. */
  22.  
  23. var sum = q.Sum(a => a.Age);
  24. /*
  25. * SELECT SUM([Users].[Age]) AS [C] FROM [Users] AS [Users]
  26. */
  27.  
  28. var max = q.Max(a => a.Age);
  29. /*
  30. * SELECT MAX([Users].[Age]) AS [C] FROM [Users] AS [Users]
  31. */
  32.  
  33. var min = q.Min(a => a.Age);
  34. /*
  35. * SELECT MIN([Users].[Age]) AS [C] FROM [Users] AS [Users]
  36. */
  37.  
  38. var avg = q.Average(a => a.Age);
  39. /*
  40. * SELECT CAST(AVG([Users].[Age]) AS FLOAT) AS [C] FROM [Users] AS [Users]
  41. */

分组查询

  1. IQuery<User> q = context.Query<User>();
  2.  
  3. IGroupingQuery<User> g = q.Where(a => a.Id > 0).GroupBy(a => a.Age);
  4. g = g.Having(a => a.Age > 1 && DbFunctions.Count() > 0);
  5.  
  6. g.Select(a => new { a.Age, Count = DbFunctions.Count(), Sum = DbFunctions.Sum(a.Age), Max = DbFunctions.Max(a.Age), Min = DbFunctions.Min(a.Age), Avg = DbFunctions.Average(a.Age) }).ToList();
  7. /*
  8. * SELECT [Users].[Age] AS [Age],COUNT(1) AS [Count],SUM([Users].[Age]) AS [Sum],MAX([Users].[Age]) AS [Max],MIN([Users].[Age]) AS [Min],CAST(AVG([Users].[Age]) AS FLOAT) AS [Avg] FROM [Users] AS [Users] WHERE [Users].[Id] > 0 GROUP BY [Users].[Age] HAVING ([Users].[Age] > 1 AND COUNT(1) > 0)
  9. */

SqlQuery

上面是纯面向对象的方式查询。连接查询、聚合查询、分组查询如此轻松,有没有觉得很方便?当然,始终和 linq 那种接近 sql 的 from v in q where v > 3 select v 写法没法比!同时,ORM始终是个工具,它并不是万能的,对于一些复杂的语句,还是得需要手写,因此,DbContext 也提供原生 sql 查询接口:

  1. context.SqlQuery<User>("select Id,Name,Age from Users where Name=@name", DbParam.Create("@name", "lu")).ToList();
  2. context.SqlQuery<int>("select Id from Users").ToList();

经测试,非 Debug 情况下,且都经过预热后,相同的查询在速度、性能上与 Dapper 相当,甚至比 Dapper 还快那么一丢丢。

使用进阶

IQuery<T> 接口支持连接查询、聚合查询、分组查询,这几个接口配合使用可以减少很多我们开发中的烦恼。比如:

去视图

做数据库开发,多表关联的数据结构肯定不少,难免会有多表连接查询,很多时候,为了方便查询,一般我们都会建立视图。在我看来视图很烦,真的烦。

int 烦 = 0;

1.建视图的时候,字段多的话,烦++,如果出现字段重名的情况,必须起别名,烦++。

2.视图建立起来了以后,查询是方便了,但后面维护就不那么友好了,比如某个表字段名改了、增加一个字段、删除一个字段等情况,得修改相应的视图(1个或多个),烦++;同时又要去修改相映射的实体,烦++。总之,Console.Write("烦烦烦: " + 烦.ToString()); 对于我这种懒程序员,这简直就是种煎熬!如果一套 ORM 支持连接查询,在一定程度上可以减少在数据库上建视图数量,无形中省出好多时间。

为了让 Chloe 支持连接查询,费了我不少劲。连接查询的好处可以看上面连接查询部分。

勉强应付一些复杂查询

比如,本文中的 User 表、City 表,他们的关系是一个 User 隶属一个 City,一个 City 有多个用户。假设,现在有需求要查出 City 的信息,同时也要把该 City 下用户最小的年龄输出,如果用原生 sql 写的话大概是:

  1. select City.*,T.MinAge from City left join (select CityId,Min(Users.Age) as MinAge from Users group by Users.CityId) as T on City.Id=T.CityId

虽然也不是很复杂。来看看 Chloe 如何实现:

  1. IQuery<User> users = context.Query<User>();
  2. IQuery<City> cities = context.Query<City>();
  3. var gq = users.GroupBy(a => a.CityId).Select(a => new { a.CityId, MinAge = DbFunctions.Min(a.Age) });
  4.  
  5. cities.LeftJoin(gq, (city, g) => city.Id == g.CityId).Select((city, g) => new { City = city, MinAge = g.MinAge }).ToList();
  6. /*
  7. * SELECT [T].[MinAge] AS [MinAge],[City].[Id] AS [Id],[City].[Name] AS [Name],[City].[ProvinceId] AS [ProvinceId] FROM [City] AS [City] LEFT JOIN (SELECT [Users].[CityId] AS [CityId],MIN([Users].[Age]) AS [MinAge] FROM [Users] AS [Users] GROUP BY [Users].[CityId]) AS [T] ON [City].[Id] = [T].[CityId]
  8. */

完全可以用面向对象的方式就可以实现,怎么样?很实用吧,免去拼 sql,让更多的时间去做业务开发!

更多的用法还有待挖掘。

支持的lambda

Chloe 查询条件依赖 lambda 表达式,从对 lambda 表达式树零认知到完成对其解析这块,花了我好多精力,费了好多神,掉了不少头发。现在对谓语支持很丰富,可以说爱怎么写就怎么写~

  1. IQuery<User> q = context.Query<User>();
  2.  
  3. List<int> ids = new List<int>();
  4. ids.Add(1);
  5. ids.Add(2);
  6. ids.Add(2);
  7.  
  8. string name = "lu";
  9. string nullString = null;
  10. bool b = false;
  11. bool b1 = true;
  12.  
  13. q.Where(a => true).ToList();
  14. q.Where(a => a.Id == 1).ToList();
  15. q.Where(a => a.Id == 1 || a.Id > 1).ToList();
  16. q.Where(a => a.Id == 1 && a.Name == name && a.Name == nullString && a.Id == FeatureTest.ID).ToList();
  17. q.Where(a => ids.Contains(a.Id)).ToList();
  18. q.Where(a => !b == (a.Id > 0)).ToList();
  19. q.Where(a => a.Id > 0).Where(a => a.Id == 1).ToList();
  20. q.Where(a => !(a.Id > 10)).ToList();
  21. q.Where(a => !(a.Name == name)).ToList();
  22. q.Where(a => a.Name != name).ToList();
  23. q.Where(a => a.Name == name).ToList();
  24. q.Where(a => (a.Name == name) == (a.Id > 0)).ToList();
  25. q.Where(a => a.Name == (a.Name ?? name)).ToList();
  26. q.Where(a => (a.Age == null ? 0 : 1) == 1).ToList();
  27.  
  28. //运算操作符
  29. q.Select(a => new
  30. {
  31. Add = 1 + 2,
  32. Subtract = 2 - 1,
  33. Multiply = 2 * 11,
  34. Divide = 4 / 2,
  35. And = true & false,
  36. IntAnd = 1 & 2,
  37. Or = true | false,
  38. IntOr = 3 | 1,
  39. }).ToList();

常用的函数

  1. IQuery<User> q = context.Query<User>();
  2.  
  3. var space = new char[] { ' ' };
  4.  
  5. DateTime startTime = DateTime.Now;
  6. DateTime endTime = DateTime.Now.AddDays(1);
  7. q.Select(a => new
  8. {
  9. Id = a.Id,
  10.  
  11. String_Length = (int?)a.Name.Length,//LEN([Users].[Name])
  12. Substring = a.Name.Substring(0),//SUBSTRING([Users].[Name],0 + 1,LEN([Users].[Name]))
  13. Substring1 = a.Name.Substring(1),//SUBSTRING([Users].[Name],1 + 1,LEN([Users].[Name]))
  14. Substring1_2 = a.Name.Substring(1, 2),//SUBSTRING([Users].[Name],1 + 1,2)
  15. ToLower = a.Name.ToLower(),//LOWER([Users].[Name])
  16. ToUpper = a.Name.ToUpper(),//UPPER([Users].[Name])
  17. IsNullOrEmpty = string.IsNullOrEmpty(a.Name),//太长,不贴了
  18. Contains = (bool?)a.Name.Contains("s"),//太长,略
  19. Trim = a.Name.Trim(),//RTRIM(LTRIM([Users].[Name]))
  20. TrimStart = a.Name.TrimStart(space),//LTRIM([Users].[Name])
  21. TrimEnd = a.Name.TrimEnd(space),//RTRIM([Users].[Name])
  22. StartsWith = (bool?)a.Name.StartsWith("s"),//太长,略
  23. EndsWith = (bool?)a.Name.EndsWith("s"),//太长,略
  24.  
  25. SubtractTotalDays = endTime.Subtract(startTime).TotalDays,//CAST(DATEDIFF(DAY,@P_0,@P_1)
  26. SubtractTotalHours = endTime.Subtract(startTime).TotalHours,//CAST(DATEDIFF(HOUR,@P_0,@P_1)
  27. SubtractTotalMinutes = endTime.Subtract(startTime).TotalMinutes,//CAST(DATEDIFF(MINUTE,@P_0,@P_1)
  28. SubtractTotalSeconds = endTime.Subtract(startTime).TotalSeconds,//CAST(DATEDIFF(SECOND,@P_0,@P_1)
  29. SubtractTotalMilliseconds = endTime.Subtract(startTime).TotalMilliseconds,//CAST(DATEDIFF(MILLISECOND,@P_0,@P_1)
  30.  
  31. Now = DateTime.Now,//GETDATE()
  32. UtcNow = DateTime.UtcNow,//GETUTCDATE()
  33. Today = DateTime.Today,//CAST(GETDATE() AS DATE)
  34. Date = DateTime.Now.Date,//CAST(GETDATE() AS DATE)
  35. Year = DateTime.Now.Year,//DATEPART(YEAR,GETDATE())
  36. Month = DateTime.Now.Month,//DATEPART(MONTH,GETDATE())
  37. Day = DateTime.Now.Day,//DATEPART(DAY,GETDATE())
  38. Hour = DateTime.Now.Hour,//DATEPART(HOUR,GETDATE())
  39. Minute = DateTime.Now.Minute,//DATEPART(MINUTE,GETDATE())
  40. Second = DateTime.Now.Second,//DATEPART(SECOND,GETDATE())
  41. Millisecond = DateTime.Now.Millisecond,//DATEPART(MILLISECOND,GETDATE())
  42. DayOfWeek = DateTime.Now.DayOfWeek,//(DATEPART(WEEKDAY,GETDATE()) - 1)
  43.  
  44. Int_Parse = int.Parse(""),//CAST(N'1' AS INT)
  45. Int16_Parse = Int16.Parse(""),//CAST(N'11' AS SMALLINT)
  46. Long_Parse = long.Parse(""),//CAST(N'2' AS BIGINT)
  47. Double_Parse = double.Parse(""),//CAST(N'3' AS FLOAT)
  48. Float_Parse = float.Parse(""),//CAST(N'4' AS REAL)
  49. Decimal_Parse = decimal.Parse(""),//CAST(N'5' AS DECIMAL)
  50. Guid_Parse = Guid.Parse("D544BC4C-739E-4CD3-A3D3-7BF803FCE179"),//CAST(N'xxx' AS UNIQUEIDENTIFIER) AS [Guid_Parse]
  51.  
  52. Bool_Parse = bool.Parse(""),//CASE WHEN CAST(N'1' AS BIT) = CAST(1 AS BIT) THEN CAST(1 AS BIT) WHEN NOT (CAST(N'1' AS BIT) = CAST(1 AS BIT)) THEN CAST(0 AS BIT) ELSE NULL END AS [Bool_Parse]
  53. DateTime_Parse = DateTime.Parse("1992-1-16"),//CAST(N'1992-1-16' AS DATETIME) AS [DateTime_Parse]
  54.  
  55. B = a.Age == null ? false : a.Age > 1,
  56. }).ToList();

Chloe 的查询,基本就这些用法。因为查询接口直接借鉴 linq,所以,看起来就好像在介绍 linq 一样,抱歉- -。也正因为这点,之前我把项目中的 EF 替换成 Chloe 的时候,因为我个人不怎么用 linq 的 from in select 那种语法,所以,替换的时候几乎不用改什么代码,就可以成功编译运行。EF 对实体间的关系处理得非常好,如一对多,一对一导航,Chloe 倒没那么强大。就目前的 Chloe 的 Query 接口,基本可以满足大部分查询需求了。

现在市面上各种ORM,层出不穷,有人可能会问 LZ 为什么还要重复造轮子?

  1. 这确实是一个ORM齐放的年代,各色各样,千奇百怪的都有。但让人满意的框架(EF除外,EF在我心中是神一样的存在)少之又少。做得不错的,也总有些方面不足,恰恰却因为一些小小的不足让我止步,如实体复杂,不支持 lambda,支持lambda的但支持的写法又不多,连接查询不是很友好、便捷等等,都怪我太挑剔,抱歉。
  2. 文章开头也说过,增删查改,烦了。想用业余时间做点有意思的东西,提升自己编码能力的同时也可以学到更多知识。因为写了这个框架,我对面对对象的理解更加深刻了,如果不尝试的话,我估计我在程序员职业生涯内连个抽象类、接口都不会设计,更别说会什么设计模式,面对对象编程原则了。之所以选择做 ORM,因为 ORM 很贴切我们日常开发,只要涉及数据库,就可以用到!
  3. 如果上面两点还不足以让您明白我为什么要造轮子,那最后我要告诉您的是:我是一枚任性的程序员,我就是要造轮子!

结语

Chloe.ORM 完全开源,遵循 Apache2.0 协议,托管于GitHub,供大伙学习参考,如果能参与开发与完善 Chloe 那再好不过了,项目地址:https://github.com/shuxinqin/Chloe。感兴趣或觉得不错的望赏个star,不胜感激!

若能顺手点个赞,更加感谢!

[开源].NET数据库访问框架Chloe.ORM的更多相关文章

  1. [开源]无sql之旅-Chloe.ORM之增删查改

    扯淡 这是一款轻量.高效的.NET C#数据库访问框架(ORM).查询接口借鉴 Linq(但不支持 Linq).借助 lambda 表达式,可以完全用面向对象的方式就能轻松执行多表连接查询.分组查询. ...

  2. 类EF框架Chloe.ORM升级:只为更完美

    扯淡 Chloe.ORM:一款轻量.高效的.NET C#数据库访问框架(ORM).查询接口借鉴 Linq(但不支持 Linq).借助 lambda 表达式,可以完全用面向对象的方式就能轻松执行多表连接 ...

  3. “Zhuang.Data”轻型数据库访问框架(一)开篇介绍

    目录: “Zhuang.Data”轻型数据库访问框架(一)开篇介绍 “Zhuang.Data”轻型数据库访问框架(二)框架的入口DbAccessor对象 框架介绍 该框架主要用于数据库访问,封装了包括 ...

  4. “Zhuang.Data”轻型数据库访问框架(二)框架的入口DbAccessor对象

    目录: “Zhuang.Data”轻型数据库访问框架(一)开篇介绍 “Zhuang.Data”轻型数据库访问框架(二)框架的入口DbAccessor对象 先来看一段代码 DbAccessor dba ...

  5. Spring+Mybatis+Mysql搭建分布式数据库访问框架

    一.前言 用Java开发企业应用软件, 经常会采用Spring+MyBatis+Mysql搭建数据库框架.如果数据量很大,一个MYSQL库存储数据访问效率很低,往往会采用分库存储管理的方式.本文讲述如 ...

  6. SpringBoot入门 (四) 数据库访问之JdbcTemplate

    本文记录在SpringBoot中使用JdbcTemplate访问数据库. 一 JDBC回顾 最早是在上学时接触的使用JDBC访问数据库,主要有以下几个步骤: 1 加载驱动 Class.forName( ...

  7. 高品质开源工具Chloe.ORM:支持存储过程与Oracle

    扯淡 这是一款高质量的.NET C#数据库访问框架(ORM).查询接口借鉴 Linq.借助 lambda 表达式,可以完全用面向对象的方式就能轻松执行多表连接查询.分组查询.聚合查询.插入数据.批量删 ...

  8. [开源].NET高性能框架Chloe.ORM-完美支持SQLite

    扯淡 这是一款轻量.高效的.NET C#数据库访问框架(ORM).查询接口借鉴 Linq(但不支持 Linq).借助 lambda 表达式,可以完全用面向对象的方式就能轻松执行多表连接查询.分组查询. ...

  9. [开源].NET高性能框架Chloe.ORM-完美支持.NET Core

    扯淡 这是一款轻量.高效的.NET C#数据库访问框架(ORM).查询接口借鉴 Linq(但不支持 Linq).借助 lambda 表达式,可以完全用面向对象的方式就能轻松执行多表连接查询.分组查询. ...

随机推荐

  1. 不得不吐槽的Android PopupWindow的几个痛点(实现带箭头的上下文菜单遇到的坑)

    说到PopupWindow,我个人感觉是又爱又恨,没有深入使用之前总觉得这个东西应该很简单,很好用,但是真正使用PopupWindow实现一些效果的时候总会遇到一些问题,但是即便是人家的api有问题, ...

  2. pycharm连接mysql数据库

    新的环境配置pycharm的项目时,发现pycharm不能连接到mysql数据库.由于安了java环境但是还没配置相关的库,并且jetbrains家的IDE一般都是java写的,于是猜想可能是java ...

  3. 翻译:使用 ASP.NET MVC 4, EF, Knockoutjs and Bootstrap 设计和开发站点 - 2

    我们的目标: 需求 Screen 1: 联系人列表 - 查看所有联系人 1.1 这个 screen 将显示数据库中的所有联系人. 1.2 用户可以删除任何联系人.1.3 用户可以编辑任何联系人的详细信 ...

  4. StringBuilder的使用

    今天用到了StringBuilder来拼接查询语句,发现这个真好用,决定做个小结. 百度一个StringBuilder的定义:String 对象是不可改变的.每次使用 System.String 类中 ...

  5. C语言计算2个数的最小公倍数

    #include<stdio.h>int main(){   int a,b,i=1,temp,lcm;   scanf("%d %d",&a,&b); ...

  6. H-1B身份六年后的延期问题

    http://www.hooyou.com/cn_version/h-1b/extension.html H-1B首次获签的在美国居留时限是三年,三年期满后还可以申请延期再续三年,总计在美国的最长时限 ...

  7. JavaWeb_day02_登录校验_查询所有员工信息_DeBug

    本文为博主辛苦总结,希望自己以后返回来看的时候理解更深刻,也希望可以起到帮助初学者的作用. 转载请注明 出自 : luogg的博客园 谢谢配合! WEB_day02 servlet 协议转对象 服务器 ...

  8. 分布式搜索elasticsearch配置文件详解

    elasticsearch的config文件夹里面有两个配置文件:elasticsearch.yml和logging.yml,第一个是es的基本配置文件,第二个是日志配置文件,es也是使用log4j来 ...

  9. MyBatis的一系列问题的处理(遍历Map集合和智能标签和属性和字段不一样的解决办法 和sql片段)(三)

    一.字段名与属性名(数据库的名字)不一样怎么办? 方案一:在小配置中配置一个resultMapper <!--方案一:resultMapper 字段名与属性名不一致 --> <res ...

  10. Android EventBus 3.0.0 使用总结

    转载请标明出处:http://www.cnblogs.com/zhaoyanjun/p/6039221.html 本文出自[赵彦军的博客] 前言 EventBus框架 EventBus是一个通用的叫法 ...