微型 ORM-FluentData 实例详解
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);
}
}
微型 ORM-FluentData 实例详解的更多相关文章
- 一对一关联查询注解@OneToOne的实例详解
表的关联查询比较复杂,应用的场景很多,本文根据自己的经验解释@OneToOne注解中的属性在项目中的应用.本打算一篇博客把增删改查写在一起,但是在改的时候遇到了一些问题,感觉挺有意思,所以写下第二篇专 ...
- Django框架 之 ORM查询操作详解
Django框架 之 ORM查询操作详解 浏览目录 一般操作 ForeignKey操作 ManyToManyField 聚合查询 分组查询 F查询和Q查询 事务 Django终端打印SQL语句 在Py ...
- 这个贴子的内容值得好好学习--实例详解Django的 select_related 和 prefetch_related 函数对 QuerySet 查询的优化
感觉要DJANGO用得好,ORM必须要学好,不管理是内置的,还是第三方的ORM. 最最后还是要到SQL.....:( 这一关,慢慢练啦.. 实例详解Django的 select_related 和 p ...
- 我的书籍《深入解析Java编译器:源码剖析与实例详解》就要出版了
一个十足的技术迷,2013年毕业,做过ERP.游戏.计算广告,在大公司呆过,但终究不满足仅对技术的应用,在2018年末离开了公司,全职写了一本书<深入解析Java编译器:源码剖析与实例详解> ...
- linux基础-磁盘阵列(RAID)实例详解
磁盘阵列(RAID)实例详解 raid技术分类 软raid技术 硬raid技术 Raid和lvm的区别 为什么选择用raid RAID详解 RAID-0 RAID-1 RAID-5 Raid-10 R ...
- Cocos2d-x 3.X手游开发实例详解
Cocos2d-x 3.X手游开发实例详解(最新最简Cocos2d-x手机游戏开发学习方法,以热门游戏2048.卡牌为例,完整再现手游的开发过程,实例丰富,代码完备,Cocos2d-x作者之一林顺和泰 ...
- JavaScript学习笔记-实例详解-类(二)
实例详解-类(二) //===给Object.prototype添加只读\不可枚举\不可配置的属性objectId(function(){ Object.defineProperty(Object ...
- JavaScript学习笔记-实例详解-类(一)
实例详解-类(一): //每个javascript函数(除了bind())都自动拥有一个prototype对象// 在未添加属性或重写prototype对象之前,它只包含唯一一个不可枚举属性const ...
- Entity Framework实例详解
Entity Framework Code First的默认行为是使用一系列约定将POCO类映射到表.然而,有时候,不能也不想遵循这些约定,那就需要重写它们.重写默认约定有两种方式:Data Anno ...
- 免费的HTML5连载来了《HTML5网页开发实例详解》连载(二)
最近新浪.百度.腾讯.京东.大众点评.淘宝等流行的网站都加大了招聘HTML5的力度,HTML5开发人员成了抢手货,本次连载的是由大众点评前端工程师和一淘网前端工程师基情奉献的<HTML5网页开发 ...
随机推荐
- iview render bug & vue namespace bug
iview render bug https://codepen.io/xgqfrms/pen/gyGjKP https://codepen.io/xgqfrms/full/gyGjKP bug &l ...
- 如何快速定位到DBGrid的某一行!!!急...
比如我查找张三,那么DBGrid就可以定位到张三那行并选中这行,除了用循环实现还有没有快速定位的方法,谢谢! 解决方案 » to SuperTitan001 那如何找到张三的这行呢?除了用循环还有什么 ...
- 二、kubernetes
一.kubernetes(简称k8s) 集群示意图 Kubernetes工作模式server-client,Kubenetes Master提供集中化管理Minions.部署1台Kubernetes ...
- 转 利用java反射实现两个具有相同属性bean赋值
package com.dobn.bdgcgl.utils; import java.lang.reflect.Field; import java.lang.reflect.Method; publ ...
- css伪元素之before和after
css里面的伪元素主要是用来给选择器设置特殊效果.根据常用性,记录before和after. “:before”伪元素用来在元素的内容前面添加新的元素.比如标题前面会有一个小方块,就可以通过‘ :be ...
- c++ 动态生成string类型的数组
定义一个字符串指针,将其初始化为空 char *a=NULL 然后输入输出 cin>>a cout<<a 编译无误,但执行会遇见错误 当为*a动态分配存储空间时,程序执行正常 ...
- webpack 配置 publicPath的理解
在学习webpack的时候,配置文件中有一个publicPath属性,一直不是很明白它到底是怎么用,也查了很多资料,得到最多的说法是当打包的时候,webpack会在静态文件路径前面添加publicPa ...
- codeforces157B
Trace CodeForces - 157B One day, as Sherlock Holmes was tracking down one very important criminal, h ...
- JAVA-Web 百度编辑器,修改默认大小
百度UEditor富文本编辑器-设置默认字体.字号.行间距及添加字体种类 如果这个还不能改变大小了,找一下在文件夹UEditor--css--中default.css文件,搜索出红色部分: grid_ ...
- Linux系统下手把手完成无人值守安装服务
刚入职的运维新手经常会被要求去做一些安装操作系统的工作,如果按照用镜像光盘安装操作系统,效率会相当低下.那么如何提升效率,搭建出一套可以批量安装Linux系统的无人值守的安装系统? PXE+TFTP+ ...