zoukankan      html  css  js  c++  java
  • FreeSql 如何实现 Sqlite 跨库查询

    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 附加两个数据库查看:

    其他说明

    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还有更多细节优化并不是路人一眼能看透,如果觉得写得不错麻烦点个赞,这也是我继续写下去的源动力。

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

  • 相关阅读:
    MongoDB 查询$关键字 $in $or $all
    MongoDB limit 选取 skip跳过 sort排序 方法
    POJ 1700
    POJ 1666
    POJ 1701
    POJ 1674
    POJ 1664
    POJ 1665
    POJ 1658
    POJ 1656
  • 原文地址:https://www.cnblogs.com/kellynic/p/10452867.html
Copyright © 2011-2022 走看看