FreeSql 如何实现 Sqlite 跨库查询

摘要:
正常的数据库都支持跨库,然而Sqlite默认不支持,或者说支持起来较为麻烦,FreeSql最关心的是通用、易用性,本文介绍FreeSql如何实现Sqlite跨库操作。故事发生在CodeFirst自由开发FreeSql支持并推荐使用CodeFirst方式开发项目,这种开发方式非常自由,如同FreeSql的命名一般。

FreeSql 是 .NetFramework 4.6+、.NetCore 下的 ORM 功能库,提供了丰富的功能,支持五种流行数据库 MySql/SqlServer/PostgreSQL/Oracle/Sqlite。

正常的数据库都支持跨库,然而 Sqlite 默认不支持,或者说支持起来较为麻烦,FreeSql 最关心的是通用、易用性,本文介绍 FreeSql 如何实现 Sqlite 跨库操作。

故事发生在 CodeFirst 自由开发

FreeSql 支持并推荐使用 CodeFirst 方式开发项目,这种开发方式非常自由,如同 FreeSql 的命名一般。

如下定义两个实体(文章、评论):

class Topic {
    public Guid Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public DateTime CreateTime { get; set; }
}
[Table(Name = "xxxtb.Comment")]
class Comment {
    public Guid Id { get; set; }
    public Guid TopicId { get; set; }
    public Topic Topic { get; set; }
    public string Nickname { get; set; }
    public string Content { get; set; }
    public DateTime CreateTime { get; set; }
}

我们希望将 Topic 的数据存到主库,Comment 的数据存到别外一个库(xxxtb)。比如使用 mysql,不指定数据库情况下,将操作当前数据库下的表。

其他 ado.net 或 ORM 将面临的问题(默认情况下):

1、驱动只打开了一个库,或者需要手工调用驱动的方法对其他库进行附加;

2、项目中可能需要定义多个 orm,实现对多个数据库的存储和查询;

3、无法使用跨库联表查询;

解决用户使用问题

使用习惯是 FreeSql 主要攻克的难题,其他数据库都行,【吐槽】就你丫的 Sqlite 奇葩,同连接下默认做不到跨库操作(或者说使用不方便)。

好在如今的 .NET 库大多数都已经开源,于是翻阅 System.Data.SQLite.Core 源码做了总结:

SQLiteConnection 连接对象在 Open 后,执行如下命令可附加多个数据库;

attach database [xxxtb.db] as [xxxtb];

于是,

第一步:实现一个扩展方法,使用 OpenAndAttach 代替 Open:

public static void OpenAndAttach(this DbConnection that, string[] attach) {
    that.Open();

    if (attach?.Any() == true) {
        var sb = new StringBuilder();
        foreach(var att in attach)
            sb.Append($"attach database [{att}] as [{att.Split('.').First()}];
");

        var cmd = that.CreateCommand();
        cmd.CommandText = sb.ToString();
        cmd.ExecuteNonQuery();
    }
}
//异步方法的实现省略...

第二步:增加 ConnectionString 参数 Attachs

Data Source=|DataDirectory|document.db;Attachs=xxxtb.db;Pooling=true;Max Pool Size=10

第三步:SqliteConnectionPool 实施

1、解析 Attachs;

var att = Regex.Split(_connectionString, @"Attachss*=s*", RegexOptions.IgnoreCase);
if (att.Length == 2) {
    //此条件说明存在,找到 Attachs 配置的值,并且它支持以逗号分割
    var idx = att[1].IndexOf(';');
    Attaches = (idx == -1 ? att[1] : att[1].Substring(0, idx)).Split(',');
}

2、将原有 Open 方法替换成 OpenAndAttach;

大功告成

编码与实施过程完成,接下来测试结果,仍然使用上方给出的两个实体类型。

static IFreeSql sqlite = new FreeSql.FreeSqlBuilder()
    .UseConnectionString(FreeSql.DataType.Sqlite, @"Data Source=|DataDirectory|document.db;Attachs=xxxtb.db;Pooling=true;Max Pool Size=10")
    .UseAutoSyncStructure(true)
    .UseLazyLoading(true)
    .Build();

//秀一波 FreeSql.Repository 扩展包
//安装方法:dotnet add package FreeSql.Repository
var topicRepository = sqlite.GetGuidRepository<Topic>();
var commentRepository = sqlite.GetGuidRepository<Comment>();

//添加测试文章
Guid topicId = FreeUtil.NewMongodbId();
topicRepository.Insert(new Topic {
    Id = FreeUtil.NewMongodbId(),
    Title = "文章标题1",
    Content = "文章内容1",
    CreateTime = DateTime.Now
});

//添加10条测试评论
var comments = Enumerable.Range(0, 10).Select(a => new Comment {
    Id = FreeUtil.NewMongodbId(),
    TopicId = topicId,
    Nickname = $"昵称{a}",
    Content = $"评论内容{a}",
    CreateTime = DateTime.Now
});
var affrows = commentRepository.Insert(comments);

var find = commentRepository.Select.Where(a => a.Topic.Title == "文章标题1").ToList();
//SELECT a."Id", a."TopicId", a."Nickname", a."Content", a."CreateTime" 
//FROM "xxxtb"."Comment" a, "Topic" a__Topic 
//WHERE (a__Topic."Title" = '文章标题1')

//find 查询出了10条数据

然后我们使用 navicat 附加两个数据库查看:

FreeSql 如何实现 Sqlite 跨库查询第1张

FreeSql 如何实现 Sqlite 跨库查询第2张

其他说明

1、FreeUtil.NewMongodbId 是生成有序的 Guid 值,在 FreeSql 中实现,其实可以使用 Guid.NewGuid,这里我承认有秀的嫌疑;

2、文章中的代码没有过多的依赖,在 vs2017+.netcore2.2 测试一次运行通过,sqlite 的优势免安装服务;

3、FreeSql 支持 CodeFirst,即建好实体运行程序,表就会创建;

4、FreeSql.Repository 是扩展包,实现通用 CURD 仓储层功能,文档:https://github.com/2881099/FreeSql/wiki/Repository

这个功能其实在 FreeSql 早期就已经实现了,但是一直没能有时间将过程经验整理成文章,今天把文章写完写全,希望能给大家带来一点“惊吓”。FreeSql还有更多细节优化并不是路人一眼能看透,如果觉得写得不错麻烦点个赞,这也是我继续写下去的源动力。

一遍看不明白的话,建议多看几遍。谢谢观看!

免责声明:文章转载自《FreeSql 如何实现 Sqlite 跨库查询》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇js获取本月,本季度,上个季度,本周,上周的起始和结束时间使用Yii框架完整搭建网站流程入门下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

SQLite本地轻量化数据库使用配置(全套)===》Net

1.NuGet管理包引用3个文件 NuGet管理包搜索引用System.Data.SQLite 作者:SQLite Development Team,自动引用3个文件 2.DbHelperSQLite帮助类(注意更换namespace demo2) using System; using System.Collections; using System....

SQLite 如何设置自增字段

SQLite 如何设置自增字段 转自:https://www.wenjiangs.com/article/sqlite-autoincrement-key.html 使用数据库的程序员都知道,一个表需要一个或多个主键,避免和其它表的数据冲突,更好的索引表数据。主键一般都是自动增长的,并且会自动创建索引。 什么是主键? 主键是表中经常有一个列或列的组合,其值...

Android类参考---SQLiteOpenHelper

public 抽象类 SQLiteOpenHelper 继承关系 java.lang.Object |____android.database.sqlite.SQLiteOpenHelper 类概要 这是一个辅助类,用来管理数据库的创建和数据库的版本。 你要创建一个这个类的子类来实现onCreate(SQLiteDatabase),onUpgrade(SQ...

(2356)SQLite多线程下的并发操作_飞翔的种子_百度空间

(2356)SQLite多线程下的并发操作_飞翔的种子_百度空间 SQLite多线程下的并发操作 这两天一直在捣鼓SQLite数据库,基本的操作就不说了,比较简单,打算有空的话另起一篇博文简单总结一下。 这里主要想探讨一下多路并发下的数据库操作 SQLite作为一款小型的嵌入式数据库,本身没有提供复杂的锁定机制,无法内部管理多路并发下的数据操作同步问题,...

用systemtap分析磁盘写入操作

用systemtap分析磁盘写入操作转载时请注明出处和作者联系方式作者联系方式:李先静 <xianjimli at hotmail dot com>这几天发现有好几块broncho开发板的FLASH坏了,broncho使用的SLC,现在的SLC写入寿命至少在10W次以上,尽管现在的测试要比正常使用高得多,也没有可能在不到一个月就坏了啊。不过最近...

sqlite乱码的解决方法

在命令行下通过sqlite3.exe创建数据库后,通过insert语句插入中文内容后,在程序或sqlite管理工具中打开乱码。网上有篇文章描述的就是这样一个过程。链接:http://www.cnblogs.com/niunan/archive/2009/10/31/1593516.html 通过谷歌资料发现,这个问题很难解决,要么插入中文乱码,要么只能显示...