日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

[开源].NET数据库访问框架Chloe.ORM

發(fā)布時間:2025/7/14 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [开源].NET数据库访问框架Chloe.ORM 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

扯淡

13年畢業(yè)之際,進(jìn)入第一家公司實(shí)習(xí),接觸了 EntityFramework,當(dāng)時就覺得這東西太牛了,訪問數(shù)據(jù)庫都可以做得這么輕松、優(yōu)雅!畢竟那時還年輕,沒見過世面。工作之前為了拿個實(shí)習(xí)機(jī)會混個工作證明,匆匆忙忙學(xué)了兩個月的 C#,就這樣,稀里糊涂的做了程序員,從此走上了一條不歸路。那會也只知道 SqlHelper,DataTable。ORM?太高大上,沒聽說過。雖然在第一家公司只呆了兩個月,但讓我認(rèn)識了 EntityFramework,從此也走上了 ORM 的不歸路...純純的實(shí)體,增改刪超級簡單,查詢?nèi)缧性屏魉?#xff0c;真心沒理由抗拒!以至于后來進(jìn)入第二家公司做開發(fā)極其不適應(yīng),因?yàn)樗麄儧]用 EF,也不用類 linq 的 ORM,他們有自己數(shù)據(jù)庫訪問框架。那套東西實(shí)體設(shè)計(jì)復(fù)雜,支持的功能少,查詢條件還依賴字符串,開發(fā)容錯率太低,DB操作入口接口設(shè)計(jì)也很重,里面方法不下60個,看心涼,用心累!那時,好懷念 EF~在新公司工作的時間內(nèi),來回都是增改頁面,做增刪查改,修復(fù)BUG,多少有點(diǎn)枯燥乏味,漸漸感覺編碼能力提升太慢。同時鑒于用公司的 ORM 也不是很順手,于是,萌生了自己寫 ORM 的念頭,再然后...Chloe.ORM 面世了~

導(dǎo)航

  • 事前準(zhǔn)備
  • 基本查詢
  • 連接查詢
  • 聚合函數(shù)
  • 分組查詢
  • Sql查詢
  • 使用進(jìn)階
  • 支持的lambda
  • 常用函數(shù)

Chloe.ORM

Chloe 查詢接口設(shè)計(jì)借(zhao)鑒(ban) linq,但不支持 linq。開發(fā)之前,我給我的 ORM 查詢條件接口定義一定要支持lambda表達(dá)式(潮流、趨勢,在這不討論表達(dá)式樹的性能)。開發(fā)之初,也有自己設(shè)計(jì)過查詢接口,想了一套又一套,始終沒 linq 設(shè)計(jì)的接口方便,后來,不想了,直接抄 linq,不解釋!前人如此偉大設(shè)計(jì),不用真對不起他們,我要站在他們的肩膀上!

先看下 IDbContext 接口:

public interface IDbContext : IDisposable {IDbSession CurrentSession { get; }IQuery<T> Query<T>() where T : new();IEnumerable<T> SqlQuery<T>(string sql, params DbParam[] parameters) where T : new();T Insert<T>(T entity);object Insert<T>(Expression<Func<T>> body);int Update<T>(T entity);int Update<T>(Expression<Func<T, T>> body, Expression<Func<T, bool>> condition);int Delete<T>(T entity);int Delete<T>(Expression<Func<T, bool>> condition);void TrackEntity(object entity); }

Chloe 操作入口是 IDbContext。IDbContext 僅有兩個 Query、兩個 Insert、兩個 Update 、兩個 Delete 和一個 TrackEntity 方法,以及一個 CurrentSession 的屬性,設(shè)計(jì)很簡單,但絕對能滿足81%的需求(多一點(diǎn)滿足,多一分熱愛)!
這篇文章,主要介紹 Query 接口使用。

事前準(zhǔn)備

實(shí)體:

public enum Gender {Man = 1,Woman }[TableAttribute("Users")] public class User {[Column(IsPrimaryKey = true)][AutoIncrementAttribute]public int Id { get; set; }public string Name { get; set; }public Gender? Gender { get; set; }public int? Age { get; set; }public int? CityId { get; set; }public DateTime? OpTime { get; set; } }public class City {[Column(IsPrimaryKey = true)]public int Id { get; set; }public string Name { get; set; }public int ProvinceId { get; set; } }public class Province {[Column(IsPrimaryKey = true)]public int Id { get; set; }public string Name { get; set; } } View Code

首先,創(chuàng)建一個 DbContext:

IDbContext context = new MsSqlContext(DbHelper.ConnectionString);

再創(chuàng)建一個 IQuery<T>:

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

基本查詢

IQuery<User> q = context.Query<User>(); q.Where(a => a.Id > 0).FirstOrDefault(); q.Where(a => a.Id > 0).ToList(); q.Where(a => a.Id > 0).OrderBy(a => a.Age).ToList(); q.Where(a => a.Id > 0).Take(999).OrderBy(a => a.Age).ToList();//分頁。避免生成的 sql 語句太長占篇幅,只選取 Id 和 Name 兩個字段 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(); /** 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*///如果需要多個條件的話 q.Where(a => a.Id > 0).Where(a => a.Name.Contains("lu")).ToList(); /** 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' + '%')*///選取指定字段 q.Select(a => new { a.Id, a.Name, a.Age }).ToList(); //或者 q.Select(a => new User() { Id = a.Id, Name = a.Name, Age = a.Age }).ToList(); /** SELECT [Users].[Id] AS [Id],[Users].[Name] AS [Name],[Users].[Age] AS [Age] FROM [Users] AS [Users]*/

連接查詢

建立連接:

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

只獲取 UserId,CityName,ProvinceName:

user_city_province.Select((user, city, province) => new { UserId = user.Id, CityName = city.Name, ProvinceName = province.Name }).Where(a => a.UserId == 1).ToList(); /** 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*/

調(diào)用 Select 方法返回一個包含所有信息的 IQuery<T> 對象:

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

查出一個用戶及其隸屬的城市和省份:

view.Where(a => a.User.Id == 1).ToList(); /** 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*/

這時候也可以選取指定的字段:

view.Where(a => a.User.Id == 1).Select(a => new { UserId = a.User.Id, CityName = a.City.Name, ProvinceName = a.Province.Name }).ToList(); /** 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*/

Chloe 也支持 Left Join、Right Join、Full Join 連接,用法和 Inner Join 一樣,就不一一介紹了。

聚合函數(shù)

IQuery<User> q = context.Query<User>();q.Select(a => DbFunctions.Count()).First(); /** SELECT TOP (1) COUNT(1) AS [C] FROM [Users] AS [Users]*/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(); /** 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]*/var count = q.Count(); /** SELECT COUNT(1) AS [C] FROM [Users] AS [Users]*/var longCount = q.LongCount(); /** SELECT COUNT_BIG(1) AS [C] FROM [Users] AS [Users]*/var sum = q.Sum(a => a.Age); /** SELECT SUM([Users].[Age]) AS [C] FROM [Users] AS [Users]*/var max = q.Max(a => a.Age); /** SELECT MAX([Users].[Age]) AS [C] FROM [Users] AS [Users]*/var min = q.Min(a => a.Age); /** SELECT MIN([Users].[Age]) AS [C] FROM [Users] AS [Users]*/var avg = q.Average(a => a.Age); /** SELECT CAST(AVG([Users].[Age]) AS FLOAT) AS [C] FROM [Users] AS [Users]*/

分組查詢

IQuery<User> q = context.Query<User>();IGroupingQuery<User> g = q.Where(a => a.Id > 0).GroupBy(a => a.Age); g = g.Having(a => a.Age > 1 && DbFunctions.Count() > 0);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(); /** 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)*/

SqlQuery

上面是純面向?qū)ο蟮姆绞讲樵?。連接查詢、聚合查詢、分組查詢?nèi)绱溯p松,有沒有覺得很方便?當(dāng)然,始終和 linq 那種接近 sql 的 from v in q where v > 3 select v 寫法沒法比!同時,ORM始終是個工具,它并不是萬能的,對于一些復(fù)雜的語句,還是得需要手寫,因此,DbContext 也提供原生 sql 查詢接口:

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

經(jīng)測試,非 Debug 情況下,且都經(jīng)過預(yù)熱后,相同的查詢在速度、性能上與 Dapper 相當(dāng),甚至比 Dapper 還快那么一丟丟。

使用進(jìn)階

IQuery<T> 接口支持連接查詢、聚合查詢、分組查詢,這幾個接口配合使用可以減少很多我們開發(fā)中的煩惱。比如:

去視圖

做數(shù)據(jù)庫開發(fā),多表關(guān)聯(lián)的數(shù)據(jù)結(jié)構(gòu)肯定不少,難免會有多表連接查詢,很多時候,為了方便查詢,一般我們都會建立視圖。在我看來視圖很煩,真的煩。

int 煩 = 0;

1.建視圖的時候,字段多的話,煩++,如果出現(xiàn)字段重名的情況,必須起別名,煩++。

2.視圖建立起來了以后,查詢是方便了,但后面維護(hù)就不那么友好了,比如某個表字段名改了、增加一個字段、刪除一個字段等情況,得修改相應(yīng)的視圖(1個或多個),煩++;同時又要去修改相映射的實(shí)體,煩++。總之,Console.Write("煩煩煩: " + 煩.ToString()); 對于我這種懶程序員,這簡直就是種煎熬!如果一套 ORM 支持連接查詢,在一定程度上可以減少在數(shù)據(jù)庫上建視圖數(shù)量,無形中省出好多時間。

為了讓 Chloe 支持連接查詢,費(fèi)了我不少勁。連接查詢的好處可以看上面連接查詢部分。

勉強(qiáng)應(yīng)付一些復(fù)雜查詢

比如,本文中的 User 表、City 表,他們的關(guān)系是一個 User 隸屬一個 City,一個 City 有多個用戶。假設(shè),現(xiàn)在有需求要查出 City 的信息,同時也要把該 City 下用戶最小的年齡輸出,如果用原生 sql 寫的話大概是:

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

雖然也不是很復(fù)雜。來看看 Chloe 如何實(shí)現(xiàn):

IQuery<User> users = context.Query<User>(); IQuery<City> cities = context.Query<City>(); var gq = users.GroupBy(a => a.CityId).Select(a => new { a.CityId, MinAge = DbFunctions.Min(a.Age) });cities.LeftJoin(gq, (city, g) => city.Id == g.CityId).Select((city, g) => new { City = city, MinAge = g.MinAge }).ToList(); /** 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]*/

完全可以用面向?qū)ο蟮姆绞骄涂梢詫?shí)現(xiàn),怎么樣?很實(shí)用吧,免去拼 sql,讓更多的時間去做業(yè)務(wù)開發(fā)!

更多的用法還有待挖掘。

支持的lambda

Chloe 查詢條件依賴 lambda 表達(dá)式,從對 lambda 表達(dá)式樹零認(rèn)知到完成對其解析這塊,花了我好多精力,費(fèi)了好多神,掉了不少頭發(fā)?,F(xiàn)在對謂語支持很豐富,可以說愛怎么寫就怎么寫~

IQuery<User> q = context.Query<User>();List<int> ids = new List<int>(); ids.Add(1); ids.Add(2); ids.Add(2);string name = "lu"; string nullString = null; bool b = false; bool b1 = true;q.Where(a => true).ToList(); q.Where(a => a.Id == 1).ToList(); q.Where(a => a.Id == 1 || a.Id > 1).ToList(); q.Where(a => a.Id == 1 && a.Name == name && a.Name == nullString && a.Id == FeatureTest.ID).ToList(); q.Where(a => ids.Contains(a.Id)).ToList(); q.Where(a => !b == (a.Id > 0)).ToList(); q.Where(a => a.Id > 0).Where(a => a.Id == 1).ToList(); q.Where(a => !(a.Id > 10)).ToList(); q.Where(a => !(a.Name == name)).ToList(); q.Where(a => a.Name != name).ToList(); q.Where(a => a.Name == name).ToList(); q.Where(a => (a.Name == name) == (a.Id > 0)).ToList(); q.Where(a => a.Name == (a.Name ?? name)).ToList(); q.Where(a => (a.Age == null ? 0 : 1) == 1).ToList();//運(yùn)算操作符 q.Select(a => new {Add = 1 + 2,Subtract = 2 - 1,Multiply = 2 * 11,Divide = 4 / 2,And = true & false,IntAnd = 1 & 2,Or = true | false,IntOr = 3 | 1, }).ToList(); View Code

常用的函數(shù)

IQuery<User> q = context.Query<User>();var space = new char[] { ' ' };DateTime startTime = DateTime.Now;DateTime endTime = DateTime.Now.AddDays(1);q.Select(a => new {Id = a.Id,String_Length = (int?)a.Name.Length,//LEN([Users].[Name])Substring = a.Name.Substring(0),//SUBSTRING([Users].[Name],0 + 1,LEN([Users].[Name]))Substring1 = a.Name.Substring(1),//SUBSTRING([Users].[Name],1 + 1,LEN([Users].[Name]))Substring1_2 = a.Name.Substring(1, 2),//SUBSTRING([Users].[Name],1 + 1,2)ToLower = a.Name.ToLower(),//LOWER([Users].[Name])ToUpper = a.Name.ToUpper(),//UPPER([Users].[Name])IsNullOrEmpty = string.IsNullOrEmpty(a.Name),//太長,不貼了Contains = (bool?)a.Name.Contains("s"),//太長,略Trim = a.Name.Trim(),//RTRIM(LTRIM([Users].[Name]))TrimStart = a.Name.TrimStart(space),//LTRIM([Users].[Name])TrimEnd = a.Name.TrimEnd(space),//RTRIM([Users].[Name])StartsWith = (bool?)a.Name.StartsWith("s"),//太長,略EndsWith = (bool?)a.Name.EndsWith("s"),//太長,略SubtractTotalDays = endTime.Subtract(startTime).TotalDays,//CAST(DATEDIFF(DAY,@P_0,@P_1)SubtractTotalHours = endTime.Subtract(startTime).TotalHours,//CAST(DATEDIFF(HOUR,@P_0,@P_1)SubtractTotalMinutes = endTime.Subtract(startTime).TotalMinutes,//CAST(DATEDIFF(MINUTE,@P_0,@P_1)SubtractTotalSeconds = endTime.Subtract(startTime).TotalSeconds,//CAST(DATEDIFF(SECOND,@P_0,@P_1)SubtractTotalMilliseconds = endTime.Subtract(startTime).TotalMilliseconds,//CAST(DATEDIFF(MILLISECOND,@P_0,@P_1)Now = DateTime.Now,//GETDATE()UtcNow = DateTime.UtcNow,//GETUTCDATE()Today = DateTime.Today,//CAST(GETDATE() AS DATE)Date = DateTime.Now.Date,//CAST(GETDATE() AS DATE)Year = DateTime.Now.Year,//DATEPART(YEAR,GETDATE())Month = DateTime.Now.Month,//DATEPART(MONTH,GETDATE())Day = DateTime.Now.Day,//DATEPART(DAY,GETDATE())Hour = DateTime.Now.Hour,//DATEPART(HOUR,GETDATE())Minute = DateTime.Now.Minute,//DATEPART(MINUTE,GETDATE())Second = DateTime.Now.Second,//DATEPART(SECOND,GETDATE())Millisecond = DateTime.Now.Millisecond,//DATEPART(MILLISECOND,GETDATE())DayOfWeek = DateTime.Now.DayOfWeek,//(DATEPART(WEEKDAY,GETDATE()) - 1)Int_Parse = int.Parse("1"),//CAST(N'1' AS INT)Int16_Parse = Int16.Parse("11"),//CAST(N'11' AS SMALLINT)Long_Parse = long.Parse("2"),//CAST(N'2' AS BIGINT)Double_Parse = double.Parse("3"),//CAST(N'3' AS FLOAT)Float_Parse = float.Parse("4"),//CAST(N'4' AS REAL)Decimal_Parse = decimal.Parse("5"),//CAST(N'5' AS DECIMAL)Guid_Parse = Guid.Parse("D544BC4C-739E-4CD3-A3D3-7BF803FCE179"),//CAST(N'xxx' AS UNIQUEIDENTIFIER) AS [Guid_Parse]Bool_Parse = bool.Parse("1"),//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]DateTime_Parse = DateTime.Parse("1992-1-16"),//CAST(N'1992-1-16' AS DATETIME) AS [DateTime_Parse]B = a.Age == null ? false : a.Age > 1, }).ToList(); View Code

Chloe 的查詢,基本就這些用法。因?yàn)椴樵兘涌谥苯咏梃b linq,所以,看起來就好像在介紹 linq 一樣,抱歉- -。也正因?yàn)檫@點(diǎn),之前我把項(xiàng)目中的 EF 替換成 Chloe 的時候,因?yàn)槲覀€人不怎么用 linq 的 from in select 那種語法,所以,替換的時候幾乎不用改什么代碼,就可以成功編譯運(yùn)行。EF 對實(shí)體間的關(guān)系處理得非常好,如一對多,一對一導(dǎo)航,Chloe 倒沒那么強(qiáng)大。就目前的 Chloe 的 Query 接口,基本可以滿足大部分查詢需求了。

現(xiàn)在市面上各種ORM,層出不窮,有人可能會問 LZ 為什么還要重復(fù)造輪子?

  • 這確實(shí)是一個ORM齊放的年代,各色各樣,千奇百怪的都有。但讓人滿意的框架(EF除外,EF在我心中是神一樣的存在)少之又少。做得不錯的,也總有些方面不足,恰恰卻因?yàn)橐恍┬⌒〉牟蛔阕屛抑共?#xff0c;如實(shí)體復(fù)雜,不支持 lambda,支持lambda的但支持的寫法又不多,連接查詢不是很友好、便捷等等,都怪我太挑剔,抱歉。
  • 文章開頭也說過,增刪查改,煩了。想用業(yè)余時間做點(diǎn)有意思的東西,提升自己編碼能力的同時也可以學(xué)到更多知識。因?yàn)閷懥诉@個框架,我對面對對象的理解更加深刻了,如果不嘗試的話,我估計(jì)我在程序員職業(yè)生涯內(nèi)連個抽象類、接口都不會設(shè)計(jì),更別說會什么設(shè)計(jì)模式,面對對象編程原則了。之所以選擇做 ORM,因?yàn)?ORM 很貼切我們?nèi)粘i_發(fā),只要涉及數(shù)據(jù)庫,就可以用到!
  • 如果上面兩點(diǎn)還不足以讓您明白我為什么要造輪子,那最后我要告訴您的是:我是一枚任性的程序員,我就是要造輪子!
  • 結(jié)語

    Chloe.ORM 完全開源,遵循 Apache2.0 協(xié)議,托管于GitHub,供大伙學(xué)習(xí)參考,如果能參與開發(fā)與完善 Chloe 那再好不過了,項(xiàng)目地址:https://github.com/shuxinqin/Chloe。感興趣或覺得不錯的望賞個star,不勝感激!

    若能順手點(diǎn)個贊,更加感謝!

    轉(zhuǎn)載于:https://www.cnblogs.com/so9527/p/5636216.html

    總結(jié)

    以上是生活随笔為你收集整理的[开源].NET数据库访问框架Chloe.ORM的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。