C# 轻量级 ORM 框架 NPoco 的简单应用

简介

NPoco 是 PetaPoco 的一个分支,具有一些额外的功能,截至现在 github 星数 839。NPoco 中文资料没多少,我是被博客园群友推荐的,这几天简单尝试了一下:

github: GitHub - schotime/NPoco: Simple microORM that maps the results of a query onto a POCO object. Project based on Schotime's branch of PetaPoco

wiki: Home · schotime/NPoco Wiki · GitHub

NPoco 支持多种数据库系统,包括但不限于以下几种:

  • Microsoft SQL Server

  • SQLite

  • MySQL

  • PostgreSQL

  • Oracle

  • Firebird

  • DB2

  • SQL CE (SQL Compact Edition)

快速入门

本文使用SQLite数据库作为示例,创建一个控制台项目,尝试一些简单的用法。

安装 NuGet 包

对于使用 NPoco 和 SQLite 的情况,只需要安装两个 NuGet 包:

  • NPoco - 这是 NPoco ORM 的核心库。

  • System.Data.SQLite 或 Microsoft.Data.Sqlite - 这是用于连接 SQLite 数据库的 ADO.NET 提供程序。

选择 System.Data.SQLite 或 Microsoft.Data.Sqlite 主要取决于正在使用的 .NET 平台:

  • .NET Core 3.1 或 .NET 5/6/7 的项目选择 Microsoft.Data.Sqlite

  • .NET Framework 或早期的 .NET Core 版本的项目选择 System.Data.SQLite

这里使用 Microsoft.Data.Sqlite ,NuGet 包安装如下:

实体类User

新建一个实体类 User ,并定义实体类和字段的映射关系,参考 官方文档 Mapping

//为了演示 TableName、Column ,表名和列名故意和实体类的属性名设置的不同
[TableName("Users")]
[PrimaryKey("UserId", AutoIncrement = true)]
public class User
{    
    public int UserId { get; set; }

    [Column("Email")]
    public string UserEmail { get; set; }

    [ComputedColumn]
    public DateTime CreateTime{ get; set; }

    [ComputedColumn]
    public DateTime UpdateTime { get;set; }

    // 重写 ToString 方法,打印实体类信息
    public override string ToString()
    {
        //SQLite存储日期和时间的方式是以UTC(协调世界时)为基准的,打印时需要转换成本地时间
        return $"UserId: {UserId}, " +
            $"Email: {UserEmail}," +
            $" CreatedTime: {CreateTime.ToLocalTime()}," +
            $" UpdateTime: {UpdateTime.ToLocalTime()}";
    }
}

上面用到的 TableName、PrimaryKey、Column 特性根据字面意思很容易理解,需要特别注意 ComputedColumn 相关的三个特性:

  • [Ignore] :此属性将被忽略,并且无法映射到此属性,可以定义一些跟数据库无关但业务需要的属性。

  • [ResultColumn] :可以映射到标有 ResultColumn 列的属性,但这些属性不会包含在插入或更新中 。需要在 SQL 中显式指定这些列,它不会包含在自动生成的 SQL 中

  • [ComputedColumn] :具有 Computed 列属性的属性的工作方式与 Result 列属性相同 ,但是它们将在 SQL 中自动选择

数据库类DbFactory

定义一个 DbFactory 类管理连接字符串和数据库实例,映射部分请参考 基于 Fluent / Convention 的映射

public static class DbFactory
{
    private static DatabaseFactory dbFactory;

    public static Database GetDatabase()
    {
        return dbFactory.GetDatabase();
    }

    static DbFactory()
    {        
        dbFactory = DatabaseFactory.Config(x =>
        {
            // 也可以在这里配置实体的映射关系
            x.UsingDatabase(() => new Database(
                "Data Source=mydatabase.db;", 
                DatabaseType.SQLite, 
                SqliteFactory.Instance)
            );             
        });
        InitDB();
    }

    static void InitDB()
    {
        // 创建数据库文件
        File.Create("mydatabase.db").Close();
        // 创建表
        using (IDatabase db = dbFactory.GetDatabase())
        {
            db.Execute(@"
                -- 创建Users表
                CREATE TABLE IF NOT EXISTS Users (
                    UserId INTEGER PRIMARY KEY AUTOINCREMENT,
                    Email TEXT,
                    CreateTime TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    UpdateTime TIMESTAMP DEFAULT CURRENT_TIMESTAMP
                );
                -- 创建触发器,在Users 表上的数据更新后自动更新 UpdateTime 字段
                CREATE TRIGGER IF NOT EXISTS update_user_time
                AFTER UPDATE OF Email, CreateTime ON Users
                BEGIN
                    UPDATE Users SET UpdateTime = CURRENT_TIMESTAMP WHERE rowid = NEW.rowid;
                END;"
            );
        }
    }
}

SQLite 并不直接支持在列定义中使用 ON UPDATE 语法,需要创建一个触发器在 Users 表上更新操作发生时自动更新 UpdateTime 字段。触发器触发时为了避免重新触发自身(递归触发),要仅在 UpdateTime 之外的字段被更新时才触发

增删改查

下面演示一下 Insert、Update、Delete、Query 等操作,主程序如下:

static void Main(string[] args)
{
    Insert();
    Select();
    Thread.Sleep(3000);
    Update();
    Delete();
}

Insert

创建一个 Insert 方法,实现单次插入和批量插入:

static void Insert()
{
    using (IDatabase db = DbFactory.GetDatabase())
    {
        Console.WriteLine("单次插入:");
        var user = new User { UserEmail = $"test@example.com" };
        db.Insert(user);
        Console.WriteLine(user.ToString());

        Console.WriteLine("批量插入:");
        List<User> users = new List<User>();
        for (int i = 0; i < 5; i++)
        {
            user = new User { UserEmail = $"test{i}@example.com" };
            users.Add(user);
        }
        var count = db.InsertBatch(users);
        Console.WriteLine($"批量插入 {count} 条记录");

        Console.WriteLine();
    }
}

Select

创建一个 Select 方法,实现常见的查询方法:

static void Select()
{
    using (IDatabase db = DbFactory.GetDatabase())
    {
        Console.WriteLine("查询所有用户:");
        var users = db.Fetch<User>();
        users.ForEach(user => Console.WriteLine(user.ToString()));
                    
        Console.WriteLine("使用SQL语句查询:");
        //下面两种方式都可以
        users = db.Query<User>("SELECT * FROM Users WHERE Email LIKE @0", "%@example.com").ToList();
        users = db.Query<User>("WHERE Email LIKE @0", "%@example.com").ToList();           
        users.ForEach(user => Console.WriteLine(user.ToString()));

        Console.WriteLine("使用LINQ语句查询ID大于1的用户,并按ID排序:");
        //推荐用法LINQ语句查询    
        users = db.Query<User>()
            .Where(x => x.UserId > 1)
            .OrderBy(x => x.UserId)
            .ToList();
        users.ForEach(user => Console.WriteLine(user.ToString()));

        Console.WriteLine("通过ID查询单个用户:");
        //SingleById还有很多变体,这里不在单独举例
        var user = db.SingleOrDefaultById<User>(1);
        Console.WriteLine(user.ToString());

        Console.WriteLine();
    }
}

注意:如果找不到记录,SingleById()方法会抛出异常,而 SingleOrDefaultById() 方法会返回 null,推荐使用 SingleOrDefaultById() 方法

Update

创建一个 Update 方法,实现单个用户更新和批量更新:

static void Update()
{
    using (IDatabase db = DbFactory.GetDatabase())
    {
        Console.WriteLine("更新单个用户:");
        var user = db.SingleById<User>(1);
        user.UserEmail = "updated@example.com";
        db.Update(user);
        Console.WriteLine(db.SingleById<User>(1).ToString());

        Console.WriteLine("批量更新 ID > 3 的用户:");
        var users = db.Query<User>()
            .Where(x => x.UserId > 3).ToList()
            .Select(x => UpdateBatch.For(x, db.StartSnapshot(x))).ToList()
            .Select(x => { x.Poco.UserEmail = "updated@example.com"; return x; })
            .ToList();
        db.UpdateBatch(users, new BatchOptions { BatchSize = 50 });
        db.Fetch<User>().ForEach(user => Console.WriteLine(user.ToString()));

        Console.WriteLine();
    }
}

注意:关于 UpdateBatch 方法的使用,官方文档没有详细说明,使用方法可以参考 UpdateTests

Delete

创建一个 Delete 方法,实现单个用户删除和批量删除:

static void Delete()
{
    using (IDatabase db = DbFactory.GetDatabase())
    {
        Console.WriteLine("删除单个用户:");
        var user = db.SingleById<User>(1);
        db.Delete(user);
        Console.WriteLine($"删除用户 {user.ToString()} 成功");

        Console.WriteLine("使用SQL构造器删除 Id > 4 的:");
        var sql = new Sql();
        sql.Append("DELETE FROM Users WHERE UserId > @0", 4);
        var count=db.Execute(sql);
        Console.WriteLine($"删除 {count} 条记录");

        Console.WriteLine("使用SQL语句删除 Id > 3 的:");
        count = db.Delete<User>("WHERE UserId > @0", 3);
        Console.WriteLine($"删除 {count} 条记录");
    }
}

总结

一些简单功能上手比较容易,代码侵入性也比较小。复杂一点的功能上手比较难,因为中文资料少、官方文档也有点落后。

一般的小项目或者小功能模块可以使用NPoco,大项目还是建议使用国产的FreeSQLSqlSugar

文章转载自:二次元攻城狮

原文链接: https://www.cnblogs.com/timefiles/p/18294967

体验地址: 引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构

相关推荐
StayInLove3 分钟前
G1垃圾回收器日志详解
java·开发语言
无尽的大道11 分钟前
Java字符串深度解析:String的实现、常量池与性能优化
java·开发语言·性能优化
爱吃生蚝的于勒14 分钟前
深入学习指针(5)!!!!!!!!!!!!!!!
c语言·开发语言·数据结构·学习·计算机网络·算法
binishuaio24 分钟前
Java 第11天 (git版本控制器基础用法)
java·开发语言·git
zz.YE26 分钟前
【Java SE】StringBuffer
java·开发语言
就是有点傻30 分钟前
WPF中的依赖属性
开发语言·wpf
洋24038 分钟前
C语言常用标准库函数
c语言·开发语言
进击的六角龙40 分钟前
Python中处理Excel的基本概念(如工作簿、工作表等)
开发语言·python·excel
wrx繁星点点41 分钟前
状态模式(State Pattern)详解
java·开发语言·ui·设计模式·状态模式
NoneCoder1 小时前
Java企业级开发系列(1)
java·开发语言·spring·团队开发·开发