zoukankan      html  css  js  c++  java
  • 非常贴心的轮子 FreeSql

    FreeSql 项目从2018年11月28日开发至今,版本已发布至 v0.3.12,版本规则:年数-月-日-当日版本号。目前主要包括 FreeSql、FreeSql.Repository 两个项目的维护和开发。这篇文章介绍有哪些贴心功能。

    错误:传入的请求具有过多的参数。该服务器支持最多 2100 个参数。请减少参数的数目,然后重新发送该请求。

    不知道其他 orm 批量添加实体到 sqlserver 有没有这个错误,FreeSql 不存在。

    实体类配置

    每款 orm 都会有自己一套实体类配置方法,当项目的实体被多个 orm 同时使用时将成为问题,因为不可能做多套配置,FreeSql 提供了以下几种的方法,免入侵式配置;

    1、如果你从数据库生成的实体,FreeSql 提供 IsConfigEntityFromDbFirst 参数,可从数据库导入主键、自键等配置信息;

    var orm = new FreeSql.FreeSqlBuilder()
        .UseConnectionString(FreeSql.DataType.MySql, "Data Source=127.0.0.1;Port=3306;User ID=root;Password=root;Initial Catalog=cccddd;Charset=utf8;SslMode=none;Max pool size=10")
        .UseAutoSyncStructure(true)
    
        //只需要在这里控制,默认为关闭状态
        .UseConfigEntityFromDbFirst(true) 
    
        .Build();
    

    2、如果你已经使用 EF 建好了实体模式,FreeSql 提供了从 EF 元数据导入;

    public static void ConfigEntity(this ICodeFirst codeFirst, IModel efmodel) {
        foreach (var type in efmodel.GetEntityTypes()) {
            codeFirst.ConfigEntity(type.ClrType, a => {
                //表名
                var relationalTableName = type.FindAnnotation("Relational:TableName");
                if (relationalTableName != null) {
                    a.Name(relationalTableName.Value?.ToString() ?? type.ClrType.Name);
                }
    
                foreach (var prop in type.GetProperties()) {
                    var freeProp = a.Property(prop.Name);
                    //列名
                    var relationalColumnName = prop.FindAnnotation("Relational:ColumnName");
                    if (relationalColumnName != null) {
                        freeProp.Name(relationalColumnName.Value?.ToString() ?? prop.Name);
                    }
                    //主键
                    freeProp.IsPrimary(prop.IsPrimaryKey());
                    //自增
                    freeProp.IsIdentity(
                        prop.ValueGenerated == ValueGenerated.Never ||
                        prop.ValueGenerated == ValueGenerated.OnAdd ||
                        prop.GetAnnotations().Where(z =>
                            z.Name == "SqlServer:ValueGenerationStrategy" && z.Value.ToString().Contains("IdentityColumn") //sqlserver 自增
                            || z.Value.ToString().Contains("IdentityColumn") //其他数据库实现未经测试
                        ).Any()
                    );
                    //可空
                    freeProp.IsNullable(prop.AfterSaveBehavior != PropertySaveBehavior.Throw);
                    //类型
                    var relationalColumnType = prop.FindAnnotation("Relational:ColumnType");
                    if (relationalColumnType != null) {
                        var dbType = relationalColumnType.ToString();
                        if (!string.IsNullOrEmpty(dbType)) {
                            var maxLength = prop.FindAnnotation("MaxLength");
                            if (maxLength != null)
                                dbType += $"({maxLength})";
                            freeProp.DbType(dbType);
                        }
                    }
                }
            });
        }
    }
    

    3、如果你使用了其他 orm,FreeSql 提供 ConfigEntity,使用类似 2 的做法来完成配置导入;

    事务

    FreeSql 提供了同线程事务、对外开放事务。

    同线程事务

    假设用户购买了价值100元的商品:

    第一步:扣余额;

    第二步:扣库存;

    第一步成功了,到了第二步发现库存不足时,事务可以回滚,扣余额的数据将不生效。

    //假设已经有了其他wiki页的IFreeSql声明
    orm.Transaction(() => {
    
        var affrows = orm.Update<User>().Set(a => a.Wealth - 100)
            .Where(a => a.Wealth >= 100)
            //判断别让用户余额扣成负数
            .ExecuteAffrows();
        if (affrows < 1) {
            throw new Exception("用户余额不足");
            //抛出异常,事务退出
        }
    
        affrows = orm.Update<Goods>().Set(a => a.Stock - 1)
            .Where(a => a.Stock > 0)
            //判断别让用库存扣成负数
            .ExecuteAffrows();
        if (affrows < 1) {
            throw new Exception("商品库存不足");
            //抛出异常,回滚事务,事务退出
            //用户余额的扣除将不生效
        }
    
        //程序执行在此处,说明都扣成功了,事务完成并提交
    });
    

    注意与说明:

    1、数据库事务在线程挂载,每个线程只可开启一个事务连接,重复开启会获取线程已开启的事务;

    2、在事务代码过程中,不可使用异步方法,包括FreeSql提供的数据库异步方法,否则线程将会切换事务不生效;

    3、orm.Transaction 有防止死锁机制,60秒事务未结束的,将会被其他线程强行提交(不是回滚),可能造成不完整的事务,但仔细一想60秒还没完成的事务是什么原因呢?如果嫌60秒太少了可以在重载方法的参数中设置;

    指定事务对象

    除了上面提供的同线程事务外,FreeSql 还提供了指定事务对象的方法,将事务对象暴露给外部;

    orm.Update<xxx>().WithTransaction(指定事务)
        .Set(a => a.Clicks + 1).ExecuteAffrows();
    

    ISelect、IInsert、IUpdate、IDelete,都支持 WithTransaction 方法。

    仓储Repository

    dotnet add package FreeSql.Repository

    1、IFreeSql 的扩展方法;

    var curd1 = orm.GetRepository<Song, int>();
    var curd2 = orm.GetGuidRepository<Song>();
    

    2、继承现实;

    public class SongRepository : BaseRepository<Song, int> {
        public SongRepository(IFreeSql orm) : base(orm) {}
    
        //在这里增加 CURD 以外的方法
    }
    

    3、Autofac 注入;

    public IServiceProvider ConfigureServices(IServiceCollection services) {
        services.AddSingleton<IFreeSql>(orm);
        services.AddMvc();
    
        var builder = new ContainerBuilder();
    
        //示范全局过滤的仓储类注入,如果实体中不存在 Title 属性,则条件不生效
        builder.RegisterFreeRepositoryAddFilter<Song>(() => a => a.Title == DateTime.Now.ToString() + System.Threading.Thread.CurrentThread.ManagedThreadId);
    
        builder.Populate(services);
        var container = builder.Build();
        return new AutofacServiceProvider(container);
    }
    
    //在控制器使用
    public SongsController(GuidRepository<Song> repos1, GuidRepository<xxxx> repos2) {
    }
    

    Autofac 注入方式实现了全局【过滤与验证】的设定,方便租户功能的设计;

    表达式函数

    In查询

    var t1 = orm.Select<xxx>().Where(a => new[] { 1, 2, 3 }.Contains(a.testFieldInt)).ToSql();
    //SELECT a.`Id`, a.`Clicks`, a.`TestTypeInfoGuid`, a.`Title`, a.`CreateTime` 
    //FROM `tb_topic` a 
    //WHERE (a.`Id` in (1,2,3))
    

    查找今天创建的数据

    var t2 = orm.Select<xxx>().Where(a => a.CreateTime.Date == DateTime.Now.Date).ToSql();
    

    不提供 SqlFunc 之类的伪函数,所支持的类型基本都可以使用对应的表达式函数,例如 日期、字符串、IN查询、数组(PostgreSQL的数组)、字典(PostgreSQL HStore)等等。

    安全性

    1、避免死锁的事务,超时自动提交;

    2、未设置条件的删除、更新不生效;

    3、仓储提供 filter 验证数据,确保数据的安全性;

    ......

    更多特性可前往 wiki 中心查看

    github: https://github.com/2881099/FreeSql

    wiki: https://github.com/2881099/FreeSql/wiki/

  • 相关阅读:
    CSS基础知识点
    HTML回顾
    stringbuffer与stringbuilder与String
    事务的概念与使用
    大数据处理对象CLOG BLOG
    小却常用的小知识点和技巧
    视图
    移位运算符
    规范化与范式
    聚集索引和非聚集索引
  • 原文地址:https://www.cnblogs.com/kellynic/p/10512734.html
Copyright © 2011-2022 走看看