https://blog.csdn.net/tai532439904/article/details/77879767
環境要求
- .NET 4.0.
支持數據庫
MS SQL Server
使用本地.NET驅動程序MS SQL Azure
使用本地.NET驅動程序MS Access
使用本地.NET驅動程序Microsoft SQL Server Compact 4.0
需使用驅動 Microsoft SQL Server Compact 4.0 driverOracle
需使用驅動 ODP.NET driverMySQL
需使用驅動 MySQL Connector .NET driverSQLite
需使用驅動 SQLite ADO.NET Data ProviderPostgreSql
由Npgsql 提供IBM DB2
Sybase
由https://github.com/FredoKapo/FLUENT-ORM-ASE-PROVIDER提供
安裝
使用NuGet
- 搜索
FluentData
並安裝。不使用NuGet
- 下載zip文件。
- 解壓文件,並將文件復制到您的解決方案或項目文件夾中。
- 項目中添加對fluentdata.dll引用。
核心概念
DbContext
這是fluentdata的核心類。可以通過配置ConnectionString來定義這個類,如何連接數據庫和具體數據庫信息
DbCommand
這是負責對數據庫執行實際查詢的類。
Events
DbContext類有以下的Events(事件)支持:
- OnConnectionClosed
- OnConnectionOpened
- OnConnectionOpening
- OnErrorOnExecuted
- OnExecuting
通過使用其中任何一個,可以在事件中,記錄每個SQL查詢錯誤或者SQL查詢執行的時間等信息。
Builders
Builders(生成器)提供了一個非常好的API,用於生成SQL,用於插入、更新和刪除查詢。
Builder用來創建Insert, Update, Delete等相關的DbCommand實例。
Mapping
FluentData
可以將SQL查詢結果自動映射成一個POCO(POCO - Plain Old CLR Object)
實體類,也可以轉換成一個dynamic
(new in .NET 4)類型:
自動映射為實體類:
- 如果字段名稱不包含下划線(“_”)將自動映射到具有相同名稱的屬性上。例如,一個名為“Name”的字段將被自動映射到名也為“Name”的屬性上。
- 如果字段名包含下划線(“_”),將自動映射到嵌套屬性上。例如,例如,一個名為“Category_Name”的字段值將自動映射到名為“Category.Name”的屬性上。
如果數據庫中的字段和實體類型之間存在不匹配,則可以使用SQL中的別名關鍵字,也可以創建自己的映射方法。檢查下面的映射部分以獲取代碼示例。
自動映射為
dynamic
(動態類型)
- 動態類型的每一個字段都將被自動映射成具有有相同的名稱的屬性。例如,字段名為Name會被自動映射成名為Name的屬性。
什么時候需要釋放資源?
DbContext
需要主動釋放當你在啟用UseTransaction
或者UseSharedConnection
時DbContext
需要主動釋放當你在啟用UseMultiResult (or MultiResultSql)
時StoredProcedureBuilder
需要主動釋放當你在啟用UseMultiResult
時
在所有其他情況下處置將由fluentdata自動處理。這意味着在執行完查詢並關閉之前,數據庫連接一直是打開狀態。
代碼實例
創建和初始化一個DbContext
可以在*.config文件中配置connection string
,將connection string name
或者將整個connection string
作為參數傳遞給DbContext來創建DbContext。
重要的配置
IgnoreIfAutoMapFails – IDbContext.IgnoreIfAutoMapFails返回一個IDbContext,該實例中,如果在字段不能與屬性正確映射時是否拋出異常
創建和初始化一個DbContext
通過*.config中配置的ConnectionStringName:MyDatabase
創建一個DbContext
public IDbContext Context() { return new DbContext().ConnectionStringName("MyDatabase", new SqlServerProvider()); } // *.config文件中內容 <connectionStrings> <add name="MyDatabase" connectionString="server=MyServerAddress;uid=uid;pwd=pwd;database=MyDatabase;" /> </connectionStrings>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
調用DbContext的ConnectionString方法顯示設置connection string來創建
// public IDbContext Context() { return new DbContext().ConnectionString( "Server=MyServerAddress;Database=MyDatabase;Trusted_Connection=True;", new SqlServerProvider()); }
- 1
- 2
- 3
- 4
- 5
- 6
其他可以使用的提供器
如果你想連接其他的非SqlServer的數據庫,這是非常簡單的,只需要替換上面代碼中的“new SqlServerProvider()”為下面的數據提供器,比如 :AccessProvider
, DB2Provider
, OracleProvider
, MySqlProvider
, PostgreSqlProvider
, SqliteProvider
, SqlServerCompact
, SqlAzureProvider
, SqlServerProvider
。
查詢一組數據(Query for a list of items)
返回一組dynamic
對象
List<dynamic> products = Context.Sql("select * from Product").QueryMany<dynamic>();
- 1
返回一組強類型對象
List<Product> products = Context.Sql("select * from Product").QueryMany<Product>();
- 1
返回一組自定義的Collection
ProductionCollection products = Context.Sql("select * from Product").QueryMany<Product, ProductionCollection>();
- 1
返回
DataTable
類型:
查看下方查詢單個對象(Query for a single item)
查詢單個對象(Query for a single item)
返回一個dynamic
對象
dynamic product = Context.Sql(@"select * from Product where ProductId = 1").QuerySingle<dynamic>();
- 1
- 2
返回一個強類型對象
Product product = Context.Sql(@"select * from Product where ProductId = 1").QuerySingle<Product>();
- 1
- 2
返回一個DataTable
/** * 其實QueryMany<DataTable>和QuerySingle<DataTable>都可以用來返回DataTable, * 但考慮到QueryMany<DataTable>返回的是List<DataTable>, * 所以使用QuerySingle<DataTable>來返回DataTable更方便。 */ DataTable products = Context.Sql("select * from Product").QuerySingle<DataTable>();
- 1
- 2
- 3
- 4
- 5
- 6
查詢一個標量值
int numberOfProducts = Context.Sql(@"select count(*) from Product").QuerySingle<int>();
- 1
- 2
查詢一組標量值
List<int> productIds = Context.Sql(@"select ProductId from Product").QueryMany<int>();
- 1
- 2
查詢參數
索引形式參數:
dynamic products = Context.Sql(@"select * from Product where ProductId = @0 or ProductId = @1", 1, 2).QueryMany<dynamic>();
- 1
- 2
或者:
dynamic products = Context.Sql(@"select * from Product where ProductId = @0 or ProductId = @1") .Parameters(1, 2).QueryMany<dynamic>();
- 1
- 2
- 3
命名形式參數:
dynamic products = Context.Sql(@"select * from Product where ProductId = @ProductId1 or ProductId = @ProductId2") .Parameter("ProductId1", 1) .Parameter("ProductId2", 2) .QueryMany<dynamic>();
- 1
- 2
- 3
- 4
- 5
OutPut
形式參數:
var command = Context.Sql(@"select @ProductName = Name from Product where ProductId=1") .ParameterOut("ProductName", DataTypes.String, 100); command.Execute(); string productName = command.ParameterValue<string>("ProductName");
- 1
- 2
- 3
- 4
- 5
- 6
List
形式參數-in
查詢:
List<int> ids = new List<int>() { 1, 2, 3, 4 }; // 注意這里,不要在"in(...)"周圍有任何空格的操作符. dynamic products = Context.Sql(@"select * from Product where ProductId in(@0)", ids).QueryMany<dynamic>();
- 1
- 2
- 3
- 4
like
查詢:
string cens = "%abc%";
Context.Sql("select * from Product where ProductName like @0",cens);
- 1
- 2
映射
自動映射-數據庫對象與.Net對象自動進行1:1匹配:
List<Product> products = Context.Sql(@"select * from Product") .QueryMany<Product>();
- 1
- 2
- 3
自動映射到一個自定義的Collection
:
ProductionCollection products = Context.Sql("select * from Product").QueryMany<Product, ProductionCollection>();
- 1
如果數據庫字段和.Net對象類屬性名不一致,使用SQL別名語法AS:
/* * 在這里p.*中的ProductId和ProductName會自動映射到Prodoct.ProductId和Product.ProductName, * 而Category_CategoryId和Category_Name將映射到Product.Category.CategoryId和 Product.Category.Name */ List<Product> products = Context.Sql(@"select p.*, c.CategoryId as Category_CategoryId, c.Name as Category_Name from Product p inner join Category c on p.CategoryId = c.CategoryId") .QueryMany<Product>();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
使用dynamic
自定義映射規則:
List<Product> products = Context.Sql(@"select * from Product") .QueryMany<Product>(Custom_mapper_using_dynamic); public void Custom_mapper_using_dynamic(Product product, dynamic row) { product.ProductId = row.ProductId; product.Name = row.Name; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
使用datareader
進行自定義映射:
List<Product> products = Context.Sql(@"select * from Product") .QueryMany<Product>(Custom_mapper_using_datareader); public void Custom_mapper_using_datareader(Product product, IDataReader row) { product.ProductId = row.GetInt32("ProductId"); product.Name = row.GetString("Name"); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
或者當你需要映射到一個復合類型時,可以使用QueryComplexMany
或者QueryComplexSingle
:
var products = new List<Product>(); Context.Sql("select * from Product").QueryComplexMany<Product>(products, MapComplexProduct); private void MapComplexProduct(IList<Product> products, IDataReader reader) { var product = new Product(); product.ProductId = reader.GetInt32("ProductId"); product.Name = reader.GetString("Name"); products.Add(product); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
多結果集
FluentData支持多結果集。也就是說,可以在一次數據庫查詢中返回多個查詢結果。使用該特性的時候,記得使用類似下面的語句對查詢語句進行包裝。需要在查詢結束后把連接關閉。
/** * 執行第一個查詢時,會從數據庫取回數據。 * 執行第二個查詢的時候,FluentData可以判斷出這是一個多結果集查詢,所以會直接從第一個查詢里獲取需要的數據。 */ using (var command = Context.MultiResultSql) { List<Category> categories = command.Sql( @"select * from Category; select * from Product;").QueryMany<Category>(); List<Product> products = command.QueryMany<Product>(); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
選擇數據和分頁
選擇一個 builder
使得選擇數據和分頁更簡單:
// 通過調用Paging(1, 10),將返回前10個產品。 List<Product> products = Context.Select<Product>("p.*, c.Name as Category_Name") .From(@"Product p inner join Category c on c.CategoryId = p.CategoryId") .Where("p.ProductId > 0 and p.Name is not null") .OrderBy("p.Name") .Paging(1, 10).QueryMany();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
插入數據
使用SQL
:
int productId = Context.Sql(@"insert into Product(Name, CategoryId) values(@0, @1);") .Parameters("The Warren Buffet Way", 1) .ExecuteReturnLastId<int>();
- 1
- 2
- 3
- 4
使用builder
:
int productId = Context.Insert("Product") .Column("Name", "The Warren Buffet Way") .Column("CategoryId", 1) .ExecuteReturnLastId<int>();
- 1
- 2
- 3
- 4
使用builder
,並且自動映射:
Product product = new Product(); product.Name = "The Warren Buffet Way"; product.CategoryId = 1; // 將ProductId作為AutoMap方法的參數,是要指明ProductId不需要進行映射,因為它是一個數據庫自增長字段 product.ProductId = Context.Insert<Product>("Product", product) .AutoMap(x => x.ProductId) .ExecuteReturnLastId<int>();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
更新數據
使用SQL
:
int rowsAffected = Context.Sql(@"update Product set Name = @0 where ProductId = @1") .Parameters("The Warren Buffet Way", 1) .Execute();
- 1
- 2
- 3
- 4
使用builder
:
int rowsAffected = Context.Update("Product") .Column("Name", "The Warren Buffet Way") .Where("ProductId", 1) .Execute();
- 1
- 2
- 3
- 4
使用builder
,並且自動映射:
Product product = Context.Sql(@"select * from Product where ProductId = 1") .QuerySingle<Product>(); product.Name = "The Warren Buffet Way"; // 將ProductId作為AutoMap方法的參數,是要指明ProductId不需要進行映射,因為它不需要被更新。 int rowsAffected = Context.Update<Product>("Product", product) .AutoMap(x => x.ProductId) .Where(x => x.ProductId) .Execute();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
設置映射失敗異常是否拋出(IgnoreIfAutoMapFails)
當從數據庫中讀取,如果某些數據列不映出實體類,默認情況下,將拋出異常。
如果你想忽略異常,或者屬性不需要和數據庫對象進行映射,你可以設置IgnoreIfAutoMapFails(true)
,即可以在映射錯誤時不拋出異常
context.IgnoreIfAutoMapFails(true);
- 1
插入和更新 - 常用填充方式
var product = new Product(); product.Name = "The Warren Buffet Way"; product.CategoryId = 1; var insertBuilder = Context.Insert<Product>("Product", product).Fill(FillBuilder); var updateBuilder = Context.Update<Product>("Product", product).Fill(FillBuilder); public void FillBuilder(IInsertUpdateBuilder<Product> builder) { builder.Column(x => x.Name); builder.Column(x => x.CategoryId); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
刪除數據
使用SQL
:
int rowsAffected = Context.Sql(@"delete from Product where ProductId = 1") .Execute();
- 1
- 2
- 3
使用builder
:
int rowsAffected = Context.Delete("Product") .Where("ProductId", 1) .Execute();
- 1
- 2
- 3
存儲過程
使用SQL
:
int rowsAffected = Context.Sql(@"delete from Product where ProductId = 1") .Execute();
- 1
- 2
- 3
使用builder
:
var rowsAffected = Context.StoredProcedure("ProductUpdate") .Parameter("Name", "The Warren Buffet Way") .Parameter("ProductId", 1).Execute();
- 1
- 2
- 3
使用builder
,並且自動映射:
var product = Context.Sql("select * from Product where ProductId = 1") .QuerySingle<Product>(); product.Name = "The Warren Buffet Way"; var rowsAffected = Context.StoredProcedure<Product>("ProductUpdate", product) .AutoMap(x => x.CategoryId).Execute();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
使用builder
,並且自動映射和表達式:
var product = Context.Sql("select * from Product where ProductId = 1") .QuerySingle<Product>(); product.Name = "The Warren Buffet Way"; var rowsAffected = Context.StoredProcedure<Product>("ProductUpdate", product) .Parameter(x => x.ProductId) .Parameter(x => x.Name).Execute();
- 1
- 2
- 3
- 4
- 5
- 6
- 7
使用事物
FluentData 支持事務。如果使用事務,最好使用using語句將代碼包起來,已保證連接會被關閉。默認的,如果查詢過程發生異常,如事務不會被提交,會進行回滾。
using (var context = Context.UseTransaction(true)) { context.Sql("update Product set Name = @0 where ProductId = @1") .Parameters("The Warren Buffet Way", 1) .Execute(); context.Sql("update Product set Name = @0 where ProductId = @1") .Parameters("Bill Gates Bio", 2) .Execute(); context.Commit(); }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
實體工廠
實體工廠負責在自動映射的時候,生成對象實例。如果需要生成復雜的實例,可以自定義實體工廠:
List<Product> products = Context.EntityFactory(new CustomEntityFactory()) .Sql("select * from Product") .QueryMany<Product>(); public class CustomEntityFactory : IEntityFactory { public virtual object Resolve(Type type) { return Activator.CreateInstance(type); } }