当前位置:坤哥网-kungge-轻量级ORM框架PetaPoco使用笔记整理

轻量级ORM框架PetaPoco使用笔记整理

2017/8/17 23:12:22 kungge阅读(45) 评论(0)


PetaPoco是一个小型、快速、单文件的微型ORM(Object Relational Mapper)框架,可在.NET和Mono环境运行。

PetaPoco有如下特点:
1.PetaPoco不支持Linq语法,开发者需要手动编写SQL语句,调用PetaPoco封装的方法生成在数据库中可执行的SQL。
2.性能方面比手动编写DAL(Data Access Layer)稍差,也仅次于功能强大速度快的Dapper。
3.使用简单,不需要配置,将PetaPoco.cs文件加入项目中即可使用。
4.支持强类型POCO(Plain Old CLR Object),支持用T4模板生成类。
5.支持多种数据库: SQL Server,SQL Server CE, MySQL, PostgreSQL and Oracle。


下载


visual studio通过Nugut下载PetaPoco相关文件,你可以在Nugut官网查看PetaPoco版本信息:http://www.nuget.org/packages/petapoco
安装命令:Install-Package PetaPoco,安装完成会下载如下文件:
134d59bc-fd0d-4624-b39b-a74dfbcef4d5.png
Generated文件夹是T4模板使用,核心文件只有PetaPoco.cs,因此也可以直接拷贝该文件到项目中使用。
初次使用配置好sql连接,本次使用MySQL演示:
<add name="SqlConnectionString" connectionString="Server=localhost;Port=3308;Database=kunggewang;Uid=root; Pwd=kunggecom;AllowZeroDateTime=true;charset=utf8;" providerName="MySql.Data.MySqlClient" />


查询


本次新增一个Agency实体类作为演示:
public class Agency
{
    public int id { get; set; }
    public string agencyCode { get; set; }
    public string agencyName { get; set; }
    public DateTime createDate { get; set; }
    public int status { get; set; }
    public decimal originalDeposit { get; set; }
    public decimal leftDeposit { get; set; }
}
创建数据库表SQL语句:
CREATE TABLE `agency` (
  `id` int(11) NOT NULL,
  `agencyCode` varchar(20) NOT NULL,
  `agencyName` varchar(50) DEFAULT NULL,
  `createDate` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `status` int(11) NOT NULL DEFAULT '0',
  `originalDeposit` decimal(10,4) NOT NULL DEFAULT '0.0000',
  `leftDeposit` decimal(10,4) NOT NULL DEFAULT '0.0000',
  PRIMARY KEY (`id`),
  UNIQUE KEY `code_uq` (`agencyCode`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='机构表';

使用时首先创建一个PetaPoco.Database对象:var db = new PetaPoco.Database("SqlConnectionString");


查询多条记录:    
StringBuilder sb = new StringBuilder();
var list = db.Query<Agency>("SELECT * FROM agency");
foreach (var a in list)
{
    sb.AppendFormat("{0},{1},{2};", a.id, a.agencyCode, a.agencyName);
}

          

此外还可以调用Fetch方法查询数据,使用和Query类似,但是Fetch返回的而是POCO类的List,而Query使用yield返回数据是IEnumerable,但这些数据并未加载到内存中。
//An enumerable collection of result records
IEnumerable<Agency> listQuery = db.Query<Agency>("SELECT * FROM agency");
//A List holding the results of the query
List<Agency> listFetch=db.Fetch<Agency>("SELECT * FROM agency"));
查询一个值,如下查询记录数:
//query a scalar
long count = db.ExecuteScalar<long>("SELECT Count(*) FROM agency");

查询单条记录:

//query a single record
var oneRow = db.SingleOrDefault<Agency>("SELECT * FROM agency WHERE id=@0", 5);

还可以进行简写,PetaPoco会自动补全select关键字:var oneRow = db.SingleOrDefault<Agency>("WHERE id=@0", 5);

支持分页查询, 获取分页数据:
//Paged 分页
Sql sql = new Sql("SELECT * FROM agency where status=@0 ORDER BY id DESC", -1);
var result = db.Page<Agency>(1, 5, sql);//第一个参数是页码,第二个参数是页容量,第三个参数是SQL语句
返回的是Page对象,Page类如下:
/// <summary>
///     Holds the results of a paged request.
/// </summary>
/// <typeparam name="T">The type of Poco in the returned result set</typeparam>
public class Page<T>
{
    /// <summary>
    ///     The current page number contained in this page of result set
    /// </summary>
    public long CurrentPage { get; set; }
    /// <summary>
    ///     The total number of pages in the full result set
    /// </summary>
    public long TotalPages { get; set; }
    /// <summary>
    ///     The total number of records in the full result set
    /// </summary>
    public long TotalItems { get; set; }
    /// <summary>
    ///     The number of items per page
    /// </summary>
    public long ItemsPerPage { get; set; }
    /// <summary>
    ///     The actual records on this page
    /// </summary>
    public List<T> Items { get; set; }
    /// <summary>
    ///     User property to hold anything.
    /// </summary>
    public object Context { get; set; }
}
     
分页的相关信息到封装到了该类中,此外还提供了上Context属性,通过这个属性可以方便的传递一些上下文数据。

不带查询的命令

使用Execute执行不带查询(a non-query command)的命令:
int rtn=db.Execute("DELETE FROM agency WHERE id=@0",5);

新增

插入一条数据,需要指定表名和主键,第一个参数是表名,第二个参数是表主键,第三个参数是要新增的实体:
 //insert
Agency agency = new Agency();
agency.agencyCode = "Kungge001";
agency.agencyName = "坤哥网001";
var b = db.Insert("agency", "id", agency);

修改


修改一条数据,也需要指定表名和主键, 第一个参数是表名,第二个参数是表主键,第三个参数是要修改的实体:
//update
var updAgency = db.SingleOrDefault<Agency>("SELECT * FROM agency WHERE id=@0", 4);
updAgency.agencyName = "坤哥金融";
int u = db.Update("agency", "id", updAgency);
           
或者还可以传递一个匿名类参数来更新部分字段,如下更新agencyCode字段:
db.Update("agency", "id", new { agencyCode="WKTech001" },updAgency);
如果无法确定poco对象是新增还是修改,可以使用IsNew方法判断,使用Save方法,PetaPoco自动判断是插入还是更新记录:
if (db.IsNew(agency))
{
    //insert
}
// Save a new or existing record
db.Save(agency);
            


删除

删除一条数据:

//delete
var delAgency = db.SingleOrDefault<Agency>("SELECT * FROM agency WHERE id=@0", 6);
int d = db.Delete("agency", "id", delAgency);//第一个参数是表名,第二个参数是主键,第三个参数是实体
int d2 = db.Delete("agency", "id", null, 24);//第一个参数是表名,第二个参数是主键,第三个参数是POCO

实体若是第四个参数有值传null即可,第四个参数主键值

以上增删改操作有点麻烦,每次都要指定表名和主键。现对实体做修改,指定表名和主键:
     [TableName("agency")]
    [PrimaryKey("id")]
    public class Agency
    {
        public int id { get; set; }
        public string agencyCode { get; set; }
        public string agencyName { get; set; }
        public DateTime createDate { get; set; }
        public int status { get; set; }
        public decimal originalDeposit { get; set; }
        public decimal leftDeposit { get; set; }
    }
简化后的新增:
            //insert
            Agency agency = new Agency();
            agency.agencyCode = "Kungge0048";
            agency.agencyName = "坤哥网0048";

            var b = db.Insert(agency);


支持无标识的主键列:PrimaryKey属性类有AutoIncrement成员,表示主键列是否是自动增长,该成员默认设置为true,
 [PrimaryKey("id",AutoIncrement =true)],当Insert时返回的是主键的值。
如果没有设置这个成员值,可以通过调用Insert重载方法指定是否生成主键:
public object Insert(string tableName, string primaryKeyName, bool autoIncrement, object poco)
简化后的修改:
              var updAgency = db.SingleOrDefault<Agency>("SELECT * FROM agency WHERE id=@0", 4);
            updAgency.agencyName = "坤哥金融2";
            int u = db.Update(updAgency);
            var u2 = db.Update<Agency>("SET agencyName=@0 WHERE id=@1", "坤哥金融2", 4);

可用使用save方法来进行保存结果,不用关心是新增还是修改,db.Save(agency)。
简化后的删除:
               //delete
            var delAgency = db.SingleOrDefault<Agency>("SELECT * FROM agency WHERE id=@0", 6);
            int d = db.Delete(delAgency);
            int d2 = db.Delete<Agency>("WHERE id=@0", 6);
PetaPoco支持[Column]属性指定需要映射的列来自动匹配列,也可以使用属性[Ignore]属性忽略特定的列,[ExplicitColumns]属性表示只有明确标出的列才进行映射:
     [TableName("agency")]
    [PrimaryKey("id")]
    public class Agency
    {
        [Column]
        public int id { get; set; }
        [Column]
        public string agencyCode { get; set; }
        [Column]
        public string agencyName { get; set; }
        [Column]
        public DateTime createDate { get; set; }
        [Column]
        public int status { get; set; }
        [Column]
        public decimal originalDeposit { get; set; }
        [Ignore]
        public decimal leftDeposit { get; set; }
    }

复杂查询

查询不仅是表中的列,还会有需要计算或连接的列,在查询结果时就要将这些列填充,添加[ResultColumn]属性后会被自动填充。在使用 Update和Insert时会自动忽略,使用方法不变。
修改Agency实体类:
     [TableName("agency")]
    [PrimaryKey("id")]
    public class Agency
    {
        [Column]
        public int id { get; set; }
        [Column]
        public string agencyCode { get; set; }
        [Column]
        public string agencyName { get; set; }
        [Column]
        public DateTime createDate { get; set; }
        [Column]
        public int status { get; set; }
        [Column]
        public decimal originalDeposit { get; set; }
        [Ignore]
        public decimal leftDeposit { get; set; }
        [ResultColumn]
        public long OrderCount { get; set; }
    }
使用ResultColumn属性的列要在select中显示引用:
            //复杂查询
            var sql = new Sql(@"select `agency`.*,count(agency.agencyCode) as OrderCount
                                from `agency`
                                join `order` on `order`.agencyCode=`agency`.agencyCode
                                group by  `order`.agencyCode");
            var list=db.Query<Agency>(sql);
查询结果如下:
1c2208d8-554d-4de7-8301-f044e210bee1.png
也可以分开来写,上面的可以用下面来代替:
            var sql2 = new Sql().Select("`agency`.*,count(`agency`.agencyCode) as OrderCount").From("`agency`").InnerJoin("`order` ").On("`order`.agencyCode=`agency`.agencyCode").GroupBy("`order`.agencyCode");

            var list2 = db.Query<Agency>(sql2);


SQL Builder


使用SQL Builder使得格式化SQL语句变得简单,使用参数化SQL能防止SQL注入,而且SQL Builder消耗资源少。
            //SQL Builder
            decimal leftDeposit = 2;
            decimal originalDeposit = 10;
            var sql = Sql.Builder.Append("SELECT * FROM agency").Append("WHERE status=@0", 0);
            //sql = new Sql("SELECT * FROM agency WHERE id=@0 ",25);//还可以直接new Sql()
            //根据要求对sql拼接参数
            if (leftDeposit > 0)
            {
                sql.Append("and leftDeposit=@0", leftDeposit);
            }
            if (originalDeposit > 0)
            {
                sql.Append("and originalDeposit=@0", originalDeposit);
            }
            var agency = db.Query<Agency>(sql);
每个拼接参数都使用@0, PetaPoco最终会生成完整的参数列表,正确的更新参数。还可以使用命名的参数:
 sql.Append("and createDate>=@minCreateDate and createDate<=@maxCreateDate",new {
                minCreateDate=DateTime.Now.AddDays(-7),
                maxCreateDate=DateTime.Now
            });
设置排序:sql.OrderBy("createDate DESC");
当构建Sql对象时没有where条件,在添加刷选where条件时,PetaPoco自动处理成相应的连接符where为and,所以在添加连续where子句时,直接用where即可:
               decimal leftDeposit = 2;
            decimal originalDeposit = 10;
            var sql = Sql.Builder.Append("SELECT * FROM agency");
            //sql = new Sql("SELECT * FROM agency WHERE id=@0 ",25);//还可以直接new Sql()
            //根据要求对sql拼接参数
            if (leftDeposit > 0)
            {
                sql.Append("where leftDeposit=@0", leftDeposit);
            }
            if (originalDeposit > 0)
            {
                sql.Append("where originalDeposit=@0", originalDeposit);
            }
            var agency = db.Query<Agency>(sql);
但是要注意的是where子句必须是Sql片段的第一部分,如下将会出错:
sql.Append("where originalDeposit=@0 where originalDeposit=@1 ", leftDeposit,originalDeposit);
但是两个Append连接是可以的:
sql.Append("where leftDeposit =@0 ",leftDeposit).Append("where originalDeposit=@0", originalDeposit) ;
若是多个Append相连,where也必须是连续的,下面的就不行:
sql.Append("where leftDeposit =@0 ",leftDeposit).Append("and status=0").Append("where originalDeposit=@0", originalDeposit) ;
order by也可以多个append:
sql.Append("ORDER BY leftDeposit").Append("ORDER BY originalDeposit")

会生成:ORDER BY leftDeposit,originalDeposit


SQL命令跟踪


PetaPoco提供了三个属性用于查看最终执行的SQL语句:
LastSQL:string类型,最终执行的SQL语句
LastArgs:object[]类型,参数数组
LastCommand:string类型,最终执行的Command
如下分页获取数据例子:

16e1f886-32ed-459f-a352-4d20e2b81dc5.png


特点分析


原始版本的PetaPoco使用的是反射设置来从数据库中去读取pcoo对象的属性,反射虽然使用简单,但是性能较慢。后来PetaPoco用动态生成的的方法取代了反射,PetaPoco比典型的Linq性能要好。


T4模板


PetaPoco支持T4模板,可以自动生成PetaPoco对象,也可以生成一些常用方法,如Save(),IsNew(),Update()等。
使用T4模板很简单,总共包含三个文件,使用NuGet包下载会放在目录/Models/Generated下:
PetaPoco.Core.ttinclude:包括所有读取数据库的常规方法
PetaPoco.Generator.ttinclude:定义生成所需内容的实际模板
Database.tt:模板本身,包括各种设置和上面的两个ttinclude文件
典型的 Database.tt文件如下:
 <#@ include file="PetaPoco.Core.ttinclude" #>
<#
    // Settings
    ConnectionStringName = "jab";
    Namespace = ConnectionStringName;
    DatabaseName = ConnectionStringName;
    string RepoName = DatabaseName + "DB";
    bool GenerateOperations = true;
    // Load tables
    var tables = LoadTables();
#>
<#@ include file="PetaPoco.Generator.ttinclude" #>
如何使用模板:
1.将上面介绍的三个文件放在项目中
2.在app.config和web.config文件中设置connection和provider
3.修改Database.tt文件中的ConnectionStringName为实际值


PetaPoco

发表评论 没有账号,注册评论

博主

  • 用户名:kungge
  • 昵称:kungge

文章标签