PetaPoco笔记.docx
《PetaPoco笔记.docx》由会员分享,可在线阅读,更多相关《PetaPoco笔记.docx(44页珍藏版)》请在冰豆网上搜索。
![PetaPoco笔记.docx](https://file1.bdocx.com/fileroot1/2023-2/22/38f133b1-3afb-4adb-8d51-2010dd384107/38f133b1-3afb-4adb-8d51-2010dd3841071.gif)
PetaPoco笔记
MiniORM——PetaPoco笔记
记录一下petapoco官网博客的一些要点。
这些博客记录了PetaPoco是如何一步步改进的。
目录:
AnnouncingPetaPoco
PetaPoco-Improvements
PetaPoco-ImprovementsII
PetaPoco-T4Template
PetaPoco-NuGetPackage
PetaPoco-PagedQueries
PetaPoco-NamedColumns,ResultColumnsandint/longconversion
PetaPoco-NUnitTestCases
PetaPoco-ValueConversionsandUTCTimes
PetaPoco-T4TemplatesupportforSQLServer
SomeMinorPetaPocoImprovements
PetaPoco-TransactionBugandNamedParameterImprovements
PetaPoco-CustommappingwiththeMapperinterface
PetaPoco-SmartConsecutiveClauseHandlinginSQLBuilder
PetaPoco-PerformanceImprovementsusingDynamicMethods
PetaPoco-MoreSpeed
BenchmarkingSubSonic'sSlowPerformance
PetaPoco-SupportforSQLServerCompactEdition
PetaPoco-PostgreSQLSupportandMoreImprovements
PetaPoco-Acoupleoflittletweaks
PetaPoco-WorkingwithJoins
PetaPoco-OracleSupportandmore
PetaPoco-NotSoPoco!
(or,addingsupportfordynamic)
PetaPoco-Version2.1.0
PetaPoco-IncorporatingFeedback
PetaPoco-SingleColumnValueRequests
PetaPoco-Version3.0.0
PetaPoco-ExperimentalMultiPocoQueries
PetaPoco-What'snewinv4.0
PetaPoco-MappingOne-to-ManyandMany-to-OneRelationships
PetaPoco-PartialRecordUpdates
LongTimeNoPostandPetaPocov5
AnnouncingPetaPoco
第一个版本。
PetaPoco-Improvements
如果运行查询时不以“select”开头,则petapoco会自动加上:
//Getarecord
vara=db.SingleOrDefault("SELECT*FROMarticlesWHEREarticle_id=@0",123);
//canbeshortenedtothis:
Getarecord
vara=db.SingleOrDefault("WHEREarticle_id=@0",123);
增加了IsNew和Save方法:
如果现在有一个poco对象,要确认它是否在数据库中还是一个新记录,可以通过检查它的主键是否被设置了默认值以外的值来判断:
//Isthisanewrecord
if(db.IsNew(a))
{
//Yesitis...
}
相关的,有一个Save方法,来自动决定是插入记录还是更新记录:
//Saveaneworexistingrecord
db.Save(a);
PetaPoco-ImprovementsII
改进列映射:
PetaPoco支持[Ignore]属性来指定某个属性被忽略,现在添加了两个新属性:
[ExplicitColumns]:
添加到POCO类来表示只有明确标出的列才进行映射
[Column]:
添加到所有需要映射的列
缓存POCO类型信息
跟踪最后一个SQL语句:
公开了三个参数:
LastSQL
LastArgs:
一个Object[]数组传递的所有参数
LastCommand:
一个字符串,显示SQL和参数
可以在调试监视窗口监视LastCommand属性。
异常处理:
通过OnException方法来找出错误
一些错误:
Fetch方法返回一个List,而不是一个IEnumerable。
有些方法使用默认参数,无法与旧版本C#兼容。
自动Select无法检测到以空白开始的select语句。
MySQL参数管理和用户自定义连接字符串不能正常工作。
PetaPoco-T4Template
增加了T4模板支持:
自动生成PetaPoco对象:
[TableName("articles")]
[PrimaryKey("article_id")]
[ExplicitColumns]
publicpartialclassarticle
{
[Column]publiclongarticle_id{get;set;}
[Column]publiclongsite_id{get;set;}
[Column]publiclonguser_id{get;set;}
[Column]publicDateTime?
date_created{get;set;}
[Column]publicstringtitle{get;set;}
[Column]publicstringcontent{get;set;}
[Column]publicbooldraft{get;set;}
[Column]publiclonglocal_article_id{get;set;}
[Column]publiclong?
wip_article_id{get;set;}
}
还可以生成一些常用方法,比如Save(),IsNew(),Update(),SingleOrDefault()...可以这样使用:
vara=article.SingleOrDefault("WHEREarticle_id=@0",id);
a.Save();
T4模板从PetaPoco.Database推导出一个类来描述数据库本身,这个类有一个静态方法GetInstance(),可以用这个方法来得到数据库的实例,这样来使用:
varrecords=jabDB.GetInstance().ExecuteScalar("SELECTCOUNT(*)FROMarticles");
T4模板包括三个文件:
PetaPoco.Core.ttinclude:
包括所有读取数据库架构的常规方法
PetaPoco.Generator.ttinclude:
定义生成内容的实际模板
Records.tt:
模板本身,包括一些设置,包括其他两个模板文件
一个Records.tt文件看起来是这样的:
<#@includefile="PetaPoco.Core.ttinclude"#>
<#
//Settings
ConnectionStringName="jab";
Namespace=ConnectionStringName;
DatabaseName=ConnectionStringName;
stringRepoName=DatabaseName+"DB";
boolGenerateOperations=true;
//Loadtables
vartables=LoadTables();
#>
<#@includefile="PetaPoco.Generator.ttinclude"#>
使用模板:
添加这三个文件到C#项目。
确认在app.config或web.config里定义了数据库连接字符串connectionstringandprovidername
编辑Records.tt里的ConnectionStringName为实际的ConnectionStringName
保存Records.tt文件。
T4模板会自动生成Records.cs文件,从数据库中所有的表来生成POCO对象。
PetaPoco-NuGetPackage
现在可以从NuGet来安装了。
PetaPoco-PagedQueries
支持分页查询,通过FetchPage方法:
publicPagedFetchFetchPage(longpage,longitemsPerPage,stringsql,paramsobject[]args)whereT:
new()
注意一点page参数是从0开始。
返回值是一个PagedFetch对象:
//Resultsfrompagedrequest
publicclassPagedFetchwhereT:
new()
{
publiclongCurrentPage{get;set;}
publiclongItemsPerPage{get;set;}
publiclongTotalPages{get;set;}
publiclongTotalItems{get;set;}
publicListItems{get;set;}
}
CurrentPage和ItemsPerPage只是反映传递过来的page和itemsPerPage参数。
因为在构造分页控件的时候需要用到。
注意返回的是一个List而不是IEnumerable。
在PetaPoco里这是一个Fetch而不是一个Query。
添加一个IEnumerable版本也很简单,但考虑到结果集的大小是分页决定的,因此没必要添加。
背后的故事:
我总是觉得构建分页查询语句很乏味,这一般涉及到两个不同但很类似的SQL语句:
1.分页查询本身
2.查询所有记录数量。
接下来讲到如何处理MySQL和SQLServer分页查询的异同,为了支持不同的数据库,使用了不同的查询语句。
略过。
PetaPoco-NamedColumns,ResultColumnsandint/longconversion
命名列:
现在可以修改映射的列名称,通过给[Column]属性一个参数:
[PetaPoco.Column("article_id")]longid{get;set;}
注意,表的[PrimaryKey]属性和其他PetaPoco.Database方法的primaryKeyName参数指的是列名,不是映射的属性名。
结果列:
有时候运行查询不仅返回表中的列,还会有计算或连接的列。
我们需要查询结果能够填充这些列,但在Update和Insert操作的时候忽略它们。
为此目的增加了一个新的[ResultColumn]属性。
假设你有一个categories表,你想能够检索每个类别的文章数量。
[TableName("categories")]
[PrimaryKey("category_id")]
[ExplicitColumns]
publicclasscategory
{
[Column]publiclongcategory_id{get;set;}
[Column]publicstringname{get;set;}
[ResultColumn]publiclongarticle_count{get;set;}
}
你仍然可以像以前一样执行Update和Insert方法,aritical_count属性将被忽略。
varc=db.SingleOrDefault("WHEREname=@0","somecat");
c.name="newname";
db.Save(c);
但是你也可以用它来捕获join的结果:
varsql=newPetaPoco.Sql()
.Append("SELECTcategories.*,COUNT(article_id)asarticle_count")
.Append("FROMcategories")
.Append("JOINarticle_categoriesONarticle_categories.category_id=categories.category_id")
.Append("GROUPBYarticle_categories.category_id")
.Append("ORDERBYcategories.name");
foreach(varcindb.Fetch(sql))
{
Console.WriteLine("{0}\t{1}\t{2}",c.category_id,c.article_count,c.name);
}
注意,填充一个[ResultColumn]你必须在你的select字句中显式引用它。
PetaPoco从自动生成的select语句中生成的列中不会包括它们(比如在上一个例子中的SingleOrDefault命令)。
自动long/int转换
MySQL返回的count(*)是一个long,但是有时候把这个属性声明为int更好些。
这将在试图定义这个属性的时候导致异常。
现在PetaPoco可以自动做这个转换。
当long转换为int的时候如果值超出范围则抛出一个异常。
IDataReaders销毁
上一个版本有个bug,Fetch或Query方法后datareaders没有被销毁。
现在已经修复了这个错误。
PetaPoco-NUnitTestCases
如果要在生产环境中使用PetaPoco,很需要能够在一个更可控的方式中进行测试。
为了能够用相同的一组测试来测试SQLServer和MySQL,设置了两个连接字符串:
"mysql"和"sqlserver",然后把这些字符串当做参数来运行测试。
[TestFixture("sqlserver")]
[TestFixture("mysql")]
publicclassTests:
AssertionHelper
{
数据库不需要任何特殊的方式配置测试用例比如创建一个名为petapoco的表然后进行清理工作。
有一个嵌入式的SQL资源脚本来进行初始化和清理.
测试用例本身简单直接的使用每个特性。
对SQLbuilder功能来说也有测试用例。
主要测试都可以通过,没有任何问题。
有几个预期的SQLServer的bug已经被修正(比如FetchPage方法有一些SQL语法错误和一些类型转换问题)。
测试用例包含在github库,但NuGet包中没有。
PetaPoco-ValueConversionsandUTCTimes
这篇文章已经过时了。
PetaPoco-T4TemplatesupportforSQLServer
增加了支持SQLServer的T4模板。
SomeMinorPetaPocoImprovements
一些小的改进,让分页请求更加容易。
在使用时总是忘掉FetchPage还是PagedFetch的返回类型。
现在统一分页方法和返回类型,现在都叫做Page。
接受AdamSchroder的建议,pagenumber从1开始比从0开始更有意义。
以前的用法是这样:
PagedFetchm=user.FetchPage(page-1,30,"ORDERBYdisplay_name");
现在这样用:
Pagem=user.Page(page,30,"ORDERBYdisplay_name");
同时接受AdamSchroder的建议,现在有一个构造函数,接受一个connectionstringname和providername作为参数。
PetaPoco-TransactionBugandNamedParameterImprovements
我刚注意到(已经修复)PetaPoco的支持事务中的bug,并对Database类增加了命名参数的支持。
PetaPoco的Sqlbuilder一直支持命名参数的参数属性:
sql.Append("WHEREname=@name",new{name="petapoco"});
现在Database类也支持这个功能了:
vara=db.SingleOrDefault("WHEREname=@name",new{name="petapoco"});
PetaPoco-CustommappingwiththeMapperinterface
使用Mapper接口自定义映射
最简单的使用PetaPoco的方法是用声明哪些属性应该被映射到哪些列的属性装饰你的POCO对象。
有时候,这不太实际或有些人觉得这太有侵入性了。
所以我添加了一个声明这些绑定的方法。
PetaPoco.Database类现在支持一个叫做Mapper的静态属性,通过它你可以使用自己的列和表的映射信息。
首先,你需要提供一个PetaPoco.IMapper接口的实现:
publicinterfaceIMapper
{
voidGetTableInfo(Typet,refstringtableName,refstringprimaryKey);
boolMapPropertyToColumn(PropertyInfopi,refstringcolumnName,refboolresultColumn);
}
当GetTableInfo方法被调用时,tableName和primaryKey将被设置为PetaPoco定义的默认值,如果你需要其他的,修改即可,记得首先检查类型。
类似的,MapPropertyToColumn方法-修改columnName和resultColumn的值来适应你的需要。
允许映射返回true,或忽略它返回false。
一旦你实现了IMapper接口,你只需要设置PetaPoco的静态属性Mapper:
PetaPoco.Database.Mapper=newMyMapper();
注意这有一些限制,不过我觉得这是值得的。
1、这个mapper是被所有Database的实例共享的。
PetaPoco在全局缓存这些列映射,所以不能为不同的数据库实例提供不同的映射。
2、只能安装一个mapper。
PetaPoco-SmartConsecutiveClauseHandlinginSQLBuilder
有时需要添加多个可选的Where字句。
PetaPoco的连续子句处理可以自动正确加入它们。
想象一下,你正在查询一个数据库,有两个可选条件,一个开始日期,一个结束日期:
ListGetArticles(DateTime?
start,DateTime?
end)
{
varsql=newSql();
if(start.HasValue)
sql.Append("WHEREstart_date>=@0",start.Value);
if(end.HasValue)
{
if(start.HasValue)
sql.Append("ANDend_date<=@0",end.value);
else
sql.Append("WHEREend_data<@0",end.Value);
}
returnarticle.Fetch(sql);
}
计算第二个条件是where还是and子句很乏味。
现在