微型 ORM-FluentData 實例詳解


https://blog.csdn.net/tai532439904/article/details/77879767

環境要求

  • .NET 4.0.

支持數據庫

安裝

使用NuGet

  • 搜索FluentData並安裝。

不使用NuGet

  1. 下載zip文件。
  2. 解壓文件,並將文件復制到您的解決方案或項目文件夾中。
  3. 項目中添加對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)類型:

自動映射為實體類:

  1. 如果字段名稱不包含下划線(“_”)將自動映射到具有相同名稱的屬性上。例如,一個名為“Name”的字段將被自動映射到名也為“Name”的屬性上。
  2. 如果字段名包含下划線(“_”),將自動映射到嵌套屬性上。例如,例如,一個名為“Category_Name”的字段值將自動映射到名為“Category.Name”的屬性上。

如果數據庫中的字段和實體類型之間存在不匹配,則可以使用SQL中的別名關鍵字,也可以創建自己的映射方法。檢查下面的映射部分以獲取代碼示例。

自動映射為dynamic(動態類型)

  1. 動態類型的每一個字段都將被自動映射成具有有相同的名稱的屬性。例如,字段名為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()”為下面的數據提供器,比如 :AccessProviderDB2ProviderOracleProviderMySqlProviderPostgreSqlProviderSqliteProviderSqlServerCompactSqlAzureProviderSqlServerProvider

查詢一組數據(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); } }


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM