標籤:返回結果 很多 connect 表名 高度 expr 批量 unity 返回
Github:https://github.com/iccb1013/Sheng.SQLite.Plus
Sheng.SQLite.Plus 是一個對直接使用 ADO.NET 方式操作 SQLite 資料庫的一個增強組件,它的操作方式介於 Entity Framework 和 ADO.NET 之間,是用於 SQLite 的高度自由和高開發效率的資料庫訪問層組件。
+ 支援所有 ADO.NET 原生操作
+ 由開發人員定義模型並解除與資料庫表一一對應的關係,可由開發人員靈活指定映射關係。同一張表可以對應到多個不同的模型。
+ 支援直接使用 SQL 陳述式並根據查詢結果在記憶體中動態映射資料到模型。
+ 在大量操作資料時,支援自動化的交易處理,可自動復原。
+ 支援一對多的映射關係,即一個實體類可以映射到多張表,反之亦可。
+ 支援自動填滿/補全資料實體類中的資料,聲明模型並給定主索引值或其它條件後,可自動填滿模型。
+ 支援 DataSet、DataTable、DataRow 多種粒種的記憶體動態映射,直接從這些資料集合中產生強型別的對象集合。
+ 支援簡單 SQL 構造器,支援自動產生簡單的無模型映射的 SQL 陳述式。
+ 支援對實體欄位的精細化處理,如將實體物件的任意 Property 標記 JsonAttribute 後,將自動以 Json 格式寫入或讀取欄位。
+ 高效能,高靈活性,高可維護性。
在 Github 上,除了完整原始碼之外,還包括了一個簡單的示範程式:
現在假定有 User 表,包括四個欄位:Id,Name,Age,ExtraInfo。
我們定義一個簡單的 User 類。(亦可使用其它工具自動產生)。
public class User{ public Guid Id { get; set; } public string Name { get; set; } public int Age { get; set; } public string ExtraInfo { get; set; }}
初始化 Sheng.SQLite.Plus 核心類 DatabaseWrapper,
string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["sqlite"].ConnectionString;DatabaseWrapper database = new DatabaseWrapper(connectionString);
一、簡單資料操作
1.插入一條資料:
public void AddUser(User user){ _dataBase.Insert(user);}
Sheng.SQLite.Plus 的 Insert 方法原型是:
public bool Insert(object obj)
Insert 方法會自動解析傳入的對象執行個體,分析對象的類型名稱(User)及其所包括的屬性(Property),自動實現對 User 表及各欄位的動態映射,將資料插入到表中。
2.查詢資料
public List<User> GetUserList(){ return _dataBase.Select<User>();}
此處原理同上文一樣,Select 方法自動解析物件類型,得到表,欄位資訊,實現資料的查詢與填充。
3.修改資料
public void UpdateUser(User user){ _dataBase.Update(user);}
在 Entity Framework 中,使用跟蹤對象執行個體的變化的方式,Sheng.SQLite.Plus 沒有採用這種方式,而是直接根據提交的對象執行個體,不需要先把對象從資料庫中查詢出來。
4.刪除資料
public void RemoveUser(User user){ _dataBase.Remove(user);}
需要注意的是,使用上文中的簡單方式進行修改及刪除操作,必須在實體類中指定主鍵欄位:
public class User{ [Key] public Guid Id { get; set; } ......}
至此我們實現了基本的資料庫操作的自動化。
是不是很熟悉,和 Entity Framework 很類似是不是?
二、自訂實體類與資料庫表的映射關係
上文中的簡單增刪改查操作,是根據對象執行個體得到物件類型從而得到類型名稱和屬性(Property)集合及他們的名稱,那麼如果實體類型的名稱與資料庫表名稱並不一樣怎麼辦呢?如果資料實體的屬性(Property)與資料庫表欄位並不一一對應怎麼辦呢?
在大型項目中,這種情況是經常存在的,對於複雜的資料庫表設計,到了業務層,可能會有不同的解釋方法,例如我有一張使用者表,包含了產品不同維度資訊:基本資料、擴充資訊等。到了業務實現層面,我希望展開為兩個不同的實體物件進行操作,基本資料對象和擴充資訊對象。他們所使用的欄位可能不太相同,卻又包括了某些共通的欄位,如Id,姓名。
如上文所說,Sheng.SQLite.Plus 沒有強制的實體類與資料庫表的映射關係要求,資料庫表中的欄位多少與實體類中的屬性多少,或者說表中有的,實體類中沒有,都沒有關係,實體類中有的,通過 Attribute 標記是否映射即可。
1.資料庫表名的映射指定
我們定義兩個不同的實體類:
[Table("User")]public class User_BaseInfo{ [Key] public Guid Id { get; set; } public string Name { get; set; } public int Age { get; set; }}[Table("User")]public class User_ExtraInfo{ [Key] public Guid Id { get; set; } public string ExtraInfo { get; set; }}
只需在類型定義前加上 TableAttribute ,對 User_BaseInfo 或 User_ExtraInfo 類的對像執行個體進行操作,直接使用上文中的增刪改查方法即可。至此我們已經開始解除了實體類與資料庫表結果的強關聯。
2.資料庫表欄位的映射指定
此處嚴格來講,並非一般 ORM 中針對 資料庫表欄位 的映射,而是針對 結果集欄位 的映射。比如說通過複雜 SQL,預存程序得到的結果集,根本不是資料庫中的表。
在某些情境中,實體類中需要額外定義一些屬性,用於儲存特定資訊或實現特定功能,這些資料並不需要進行持久化儲存。或是實體類中的屬性名稱與資料庫表欄位名稱存在不完全相同的情況,如將一張表映射到多個資料實體後,為了區別描述,以及基於複雜查詢(SQL,預存程序)得到的結果集中的欄位名。
[Table("User")]public class User_ExtraInfo{ [Key] public Guid Id { get; set; } [Column("ExtraInfo")] public string Infomation { get; set; } [NotMapped] public int Count { get; set; }}
只需在屬性定義前加上 ColumnAttribute 或 NotMapped ,使用上文中的增刪改查方法即可實現相應的操作。
3.實體類對資料庫表的多對多映射
此功能用於將二維的資料庫表(或結果集)進一步強型別化。
在使用一般 ORM 架構時,對於複雜的資料庫表結構,常常可以見到非常多的欄位定義,但在我們的實際業務中,這些欄位可能都有不同的邏輯歸屬,此外,在開發中,我們可能在資料傳遞,操作的過程中,希望只傳遞或公開一部分資料,而不是整個對象進行傳遞。
public class User{ [Key] public Guid Id { get; set; } public string Name { get; set; } public int Age { get; set; } [Partial] public ExtraInfo ExtraInfo { get; set; }}public class ExtraInfo{ public string ExtraInfo { get; set; }}
只需在對象上加上 PartialAttribute ,表示屬性的對象是 當前資料集 的一部分欄位所表示的子物件。
PartialAttribute 還提供了 FieldRelationship 用來進一步指定映射關係。
這樣我們實現了實體類對資料表(資料集)的多對一映射,那如何?多對多的映射呢?實際上非常簡單,使用SQL,視圖,預存程序進行多表查詢,結合使用 PartialAttribute 即可。
三、進階操作
1.進階查詢
除了上文中提到的基本 Select<T>() 方法外,Sheng.SQLite.Plus 提供了額外的幾個進階方式進行資料查詢。
a) 基本查詢
public List<T> Select<T>() where T : class,new()
上文已展示。
b) 附加查詢條件
public List<T> Select<T>(Dictionary<string,object> attachedWhere) where T : class,new()
通過 attachedWhere 額外的指定查詢條件。Dictionary<string,object> 中的 string 和 object 分別指定欄位和欄位值。
c) 直接通過 SQL 陳述式進行查詢
public List<T> Select<T>(string sql) where T : class
直接編寫 SQL 陳述式進行資料查詢,Select 方法可根據返回的結果集和指定的物件類型進行自動對應,返回強型別對象集合。
可以傳遞任意能夠返回結果集的SQL語句,返回的結果集自動與泛型T匹配,泛型T也不一定就是資料庫中的表所映射的對象。
d) 參數化 SQL 陳述式查詢
public List<T> Select<T>(string sql, List<CommandParameter> parameterList) where T : class
進行參數化的 SQL 陳述式查詢,例如:
List<CommandParameter> parameterList = new List<CommandParameter>();parameterList.Add(new CommandParameter("@extraInfo", "ABC"));List<User> userList = _dataBase.Select<User>("SELECT * FROM [User] WHERE ExtraInfo = @extraInfo",parameterList);
2.與記憶體中的 DataSet 進行動態映射
當我們使用預存程序或其它方式得到一個 DataSet 時,Sheng.SQLite.Plus支援對其進行動態映射,根據 DataSet 資料集得到強型別的對象執行個體或對象執行個體的集合。
RelationalMappingUnity 類提供了以下方法:
public static List<T> Select<T>(DataSet ds) where T : class
將 DataSet 視為一個完整資料來源,從中尋找指定物件類型所映射的表名進行執行個體化。
public static List<T> Select<T>(DataTable dt) where T : class
使用 DataTable 作為唯一資料集,對指定的物件類型進行執行個體化。
public static T Select<T>(DataRow dr) where T : classpublic static object Select(DataRow dr, Type type)public static object Select(DataRow dr, Type type, Dictionary<string, string> fieldPair)
上面三個方法提供了更細粒度的操作可能,直接從 DataRow 得到一個強型別的對象執行個體。
3.資料填充
很多時候我們需要根據某個已知條件查詢得到對象執行個體,如我們得到 User 的 Id,希望查詢資料庫表得到 User 對象,在Sheng.SQLite.Plus中,我們使用 Fill 方法既可。
public bool Fill<T>(object obj) where T : class,new()public User GetUser(Guid id){ User user = new User(); user.Id = id; if (_dataBase.Fill<User>(user)) return user; else return null;}
Fill 方法返回一個 bool 值,表示是否成功查詢並填充了資料。
Fill 方法也有一個高階重載,可以額外指定查詢條件:
public bool Fill<T>(object obj, Dictionary<string, object> attachedWhere) where T : class,new()
4.SQL 陳述式構造器
有時,我們希望直接通過 SQL 陳述式實現對資料庫表的簡單操作,Sheng.SQLite.Plus 提供了一個 SQL 陳述式構造器,協助產生 SQL 陳述式,可以減輕開發人員編寫 SQL 陳述式的工作量和出錯的可能性,提高軟體工程的品質。
public void AddUser(User user){ SqlStructureBuild sqlStructureBuild = new SqlStructureBuild(); sqlStructureBuild.Type = SqlExpressionType.Insert; sqlStructureBuild.Table = "User"; sqlStructureBuild.AddParameter("Id", user.Id); sqlStructureBuild.AddParameter("Name", user.Name); sqlStructureBuild.AddParameter("Age", user.Age); SqlExpression sqlExpression = sqlStructureBuild.GetSqlExpression(); _dataBase.ExcuteSqlExpression(sqlExpression);}
ExcuteSqlExpression 方法在執行 SQL 構造器產生的 SqlExpression 對象時,使用的是參數化,強型別的方法進行的。
5.事務
對於連續的資料庫操作,Sheng.SQLite.Plus 自動封裝為一個事務進行執行,如果執行失敗,將自動復原。
a) 連續寫入操作
非常簡單,直接使用 Insert 方法插入一個對象集合既可,方法原型如下:
public void InsertList(List<object> objList)
串連的寫入操作時,並不要求傳入的參數是同樣類型的,也就是說可以傳入多個不同類似的實體物件,如同時傳入User和Order,Sheng.SQLite.Plus也會將其封裝為事務執行,要麼全部寫入成功,要麼復原。
b) 複雜複合操作
對於相對複雜的資料庫事務操作,可使用 SQL 陳述式構造器,分別構造 SqlExpression 對象,將其按執行順序放入集合中,通過 ExcuteSqlExpression 執行即可。
public void ExcuteSqlExpression(List<SqlExpression> sqlExpressionList)
這種方式執行的多個 SqlExpression 對象,亦封裝為事務進行執行。
Github:https://github.com/iccb1013/Sheng.SQLite.Plus
歡迎朋友們加入我們的群:
GitHub開源:SQLite 增強組件 Sheng.SQLite.Plus