From b5c62ebb7cc533b9ccb1a13dab2e7e5199d718fe Mon Sep 17 00:00:00 2001 From: 2881099 <2881099@qq.com> Date: Tue, 7 Feb 2023 19:09:32 +0800 Subject: [PATCH] =?UTF-8?q?-=20=E4=BC=98=E5=8C=96=20Firebird=20CodeFirst?= =?UTF-8?q?=20=E8=BF=81=E7=A7=BB=E4=BB=A3=E7=A0=81=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Firebird/FirebirdCodeFirstTest.cs | 23 + FreeSql/FreeSql.xml | 445 +++++++++--------- .../FirebirdCodeFirst.cs | 15 +- 3 files changed, 250 insertions(+), 233 deletions(-) diff --git a/FreeSql.Tests/FreeSql.Tests/Firebird/FirebirdCodeFirstTest.cs b/FreeSql.Tests/FreeSql.Tests/Firebird/FirebirdCodeFirstTest.cs index 66b6a9b2..760e89ae 100644 --- a/FreeSql.Tests/FreeSql.Tests/Firebird/FirebirdCodeFirstTest.cs +++ b/FreeSql.Tests/FreeSql.Tests/Firebird/FirebirdCodeFirstTest.cs @@ -10,6 +10,29 @@ namespace FreeSql.Tests.Firebird { public class FirebirdCodeFirstTest { + [Fact] + public void Issues1413() + { + var fsql = g.firebird; + fsql.Select().Count(); + } + [Table(Name = "Issues1413_client_file")] + [Index("idx_Issues1413_client_file", "cfiState, cfiBranch desc")] + public class MCliFile + { + [Column(IsPrimary = true, StringLength = 16, Position = 1)] + public string cfiNo { get; set; } + + public short cfiState { get; set; } + + [Column(StringLength = 6, CanUpdate = false, IsNullable = false)] + public string cfiBranch { get; set; } + + [Column(CanUpdate = false, IsNullable = false)] + public string cfiName { get; set; } + + } + [Fact] public void Test_0String() { diff --git a/FreeSql/FreeSql.xml b/FreeSql/FreeSql.xml index 21395735..6b8d199e 100644 --- a/FreeSql/FreeSql.xml +++ b/FreeSql/FreeSql.xml @@ -3692,234 +3692,7 @@ - - 发生的错误 - - - - - 耗时(单位:Ticks) - - - - - 耗时(单位:毫秒) - - - - - 类型 - - - - - 属性列的元数据 - - - - - 反射的属性信息 - - - - - 获取实体的属性值,也可以设置实体的属性新值 - - - - - 实体对象 - - - - - 中断实体对象审计 - false: 每个实体对象的属性都会审计(默认) - true: 每个实体对象只审计一次 - - - - - ADO.NET 数据流读取对象 - - - - - DataReader 对应的 Index 位置 - - - - - 获取 Index 对应的值,也可以设置拦截的新值 - - - - - 标识符,可将 CommandBefore 与 CommandAfter 进行匹配 - - - - - 状态数据,可与 CommandAfter 共享 - - - - - 发生的错误 - - - - - 执行SQL命令,返回的结果 - - - - - 耗时(单位:Ticks) - - - - - 耗时(单位:毫秒) - - - - - 标识符,可将 TraceBeforeEventArgs 与 TraceAfterEventArgs 进行匹配 - - - - - 状态数据,可与 TraceAfter 共享 - - - - - 备注 - - - - - 发生的错误 - - - - - 耗时(单位:Ticks) - - - - - 耗时(单位:毫秒) - - - - - 【开发环境必备】自动同步实体结构到数据库,程序运行中检查实体表是否存在,然后创建或修改 - - - - - 转小写同步结构,适用 PostgreSQL - - - - - 转大写同步结构,适用 Oracle/达梦/人大金仓 - - - - - 将数据库的主键、自增、索引设置导入,适用 DbFirst 模式,无须在实体类型上设置 [Column(IsPrimary)] 或者 ConfigEntity。此功能目前可用于 mysql/sqlserver/postgresql/oracle。 - 本功能会影响 IFreeSql 首次访问的速度。 - 若使用 CodeFirst 创建索引后,又直接在数据库上建了索引,若无本功能下一次 CodeFirst 迁移时数据库上创建的索引将被删除 - - - - - 不使用命令参数化执行,针对 Insert/Update - - - - - 是否生成命令参数化执行,针对 lambda 表达式解析 - 注意:常量不会参数化,变量才会做参数化 - var id = 100; - fsql.Select<T>().Where(a => a.id == id) 会参数化 - fsql.Select<T>().Where(a => a.id == 100) 不会参数化 - - - - - 延时加载导航属性对象,导航属性需要声明 virtual - - - - - 将实体类型与数据库对比,返回DDL语句 - - - - - - - 将实体类型集合与数据库对比,返回DDL语句 - - 实体类型 - - - - - 将实体类型与数据库对比,返回DDL语句(指定表名) - - 实体类型 - 指定表名对比 - - - - - 同步实体类型到数据库 - 注意:生产环境中谨慎使用 - - - - - - 同步实体类型集合到数据库 - 注意:生产环境中谨慎使用 - - - - - - 同步实体类型到数据库(指定表名) - 注意:生产环境中谨慎使用 - - 实体类型 - 指定表名对比 - 强制同步结构,无视缓存每次都同步 - - - - 根据 System.Type 获取数据库信息 - - - - - - - FreeSql FluentApi 配置实体,方法名与特性相同 - - - - - - - - FreeSql FluentApi 配置实体,方法名与特性相同 - - - + /param> @@ -4192,6 +3965,222 @@ 表达式 + + + 创建一个过滤器(实体类型 属于指定 TEntity 才会生效) + 场景:当登陆身份是管理员,则过滤条件不生效 + + 获取c#值 + + + + + + + 获取c#类型,int、long + + + + + + + 获取c#类型对象 + + + + + + + 获取ado.net读取方法, GetBoolean、GetInt64 + + + + + + + 序列化 + + + + + + + 反序列化 + + + + + + + 获取数据库枚举类型,适用 PostgreSQL + + + + + + + 临时 LambdaExpression.Parameter + + + + + 如果实体类有自增属性,分成两个 List,有值的Item1 merge,无值的Item2 insert + + + + + + + AsType, Ctor, ClearData 三处地方需要重新加载 + + + + + AsType, Ctor, ClearData 三处地方需要重新加载 + + + + + 动态读取 DescriptionAttribute 注释文本 + + + + + + + 通过属性的注释文本,通过 xml 读取 + + + Dict:key=属性名,value=注释 + + + + 更新实体的元数据 + + + + + 执行更新的 SQL + + + + + 执行更新命令的参数 + + + + + 执行更新命令影响的行 + + + + + 更新的实体数量 + + + + + 更新的实体 + + + + + 映射优先级,默认: Attribute > FluentApi > Aop + + + + + 实体特性 + [Table(Name = "tabname")] + [Column(Name = "table_id")] + + + + + 流式接口 + fsql.CodeFirst.ConfigEntity(a => a.Name("tabname")) + fsql.CodeFirst.ConfigEntity(a => a.Property(b => b.Id).Name("table_id")) + + + + + AOP 特性 https://github.com/dotnetcore/FreeSql/wiki/AOP + fsql.Aop.ConfigEntity += (_, e) => e.ModifyResult.Name = "public.tabname"; + fsql.Aop.ConfigEntityProperty += (_, e) => e.ModifyResult.Name = "table_id"; + + + + + 不进行任何处理 + + + + + 将帕斯卡命名字符串转换为下划线分隔字符串 + + BigApple -> Big_Apple + + + + + 将帕斯卡命名字符串转换为下划线分隔字符串,且转换为全大写 + + BigApple -> BIG_APPLE + + + + + 将帕斯卡命名字符串转换为下划线分隔字符串,且转换为全小写 + + BigApple -> big_apple + + + + + 将字符串转换为大写 + + BigApple -> BIGAPPLE + + + + + 将字符串转换为小写 + + BigApple -> bigapple + + + + + 创建一个过滤器 + 提示:在 Lambda 中判断登陆身份,请参考资料 AsyncLocal + + + 名字 + 表达式 + + + + + 创建一个动态过滤器,当 condition 返回值为 true 时才生效 + 场景:当登陆身份是管理员,则过滤条件不生效 + 提示:在 Lambda 中判断登陆身份,请参考资料 AsyncLocal + + + 名字 + 委托,返回值为 true 时才生效 + 表达式 + + + + + 创建一个过滤器(实体类型 属于指定 TEntity 才会生效) + 提示:在 Lambda 中判断登陆身份,请参考资料 AsyncLocal + + + 名字 + 表达式 + + 创建一个过滤器(实体类型 属于指定 TEntity 才会生效) diff --git a/Providers/FreeSql.Provider.Firebird/FirebirdCodeFirst.cs b/Providers/FreeSql.Provider.Firebird/FirebirdCodeFirst.cs index 0fbf6dd2..07e7addd 100644 --- a/Providers/FreeSql.Provider.Firebird/FirebirdCodeFirst.cs +++ b/Providers/FreeSql.Provider.Firebird/FirebirdCodeFirst.cs @@ -237,27 +237,32 @@ order by a.rdb$relation_name, a.rdb$field_position", tboldname ?? tbname); select trim(c.rdb$field_name), trim(d.rdb$index_name), -0, +coalesce(d.rdb$index_type, 0), case when d.rdb$unique_flag = 1 then 1 else 0 end from rdb$indices d inner join rdb$index_segments c on c.rdb$index_name = d.rdb$index_name -where d.rdb$index_type = 0 and trim(d.rdb$relation_name) = {0}", tboldname ?? tbname); +where trim(d.rdb$relation_name) = {0}", tboldname ?? tbname); var dsuk = _orm.Ado.ExecuteArray(CommandType.Text, dsuksql).Select(a => new[] { string.Concat(a[0]), string.Concat(a[1]), string.Concat(a[2]), string.Concat(a[3]) }); foreach (var uk in tb.Indexes) { if (string.IsNullOrEmpty(uk.Name) || uk.Columns.Any() == false) continue; var ukname = ReplaceIndexName(uk.Name, tbname); var dsukfind1 = dsuk.Where(a => string.Compare(a[1], ukname, true) == 0).ToArray(); - if (dsukfind1.Any() == false || dsukfind1.Length != uk.Columns.Length || dsukfind1.Where(a => (a[3] == "1") == uk.IsUnique && uk.Columns.Where(b => string.Compare(b.Column.Attribute.Name, a[0], true) == 0 && (a[2] == "1") == b.IsDesc).Any()).Count() != uk.Columns.Length) + if (dsukfind1.Any() == false || dsukfind1.Length != uk.Columns.Length || + dsukfind1.Where(a => (a[3] == "1") == uk.IsUnique && uk.Columns.Where(b => string.Compare(b.Column.Attribute.Name, a[0], true) == 0).Any()).Count() != uk.Columns.Length || + dsukfind1.Any(a => a[2] == "1") && !uk.Columns.Any(a => a.IsDesc)) { - if (dsukfind1.Any()) sb.Append("DROP INDEX ").Append(_commonUtils.QuoteSqlName(ukname)).Append(" ON ").Append(_commonUtils.QuoteSqlName(tbname)).Append(";\r\n"); + if (dsukfind1.Any()) sb.Append("DROP INDEX ").Append(_commonUtils.QuoteSqlName(ukname)) + //.Append(" ON ").Append(_commonUtils.QuoteSqlName(tbname)) + .Append(";\r\n"); sb.Append("CREATE "); if (uk.IsUnique) sb.Append("UNIQUE "); + if (uk.Columns.Any(a => a.IsDesc)) sb.Append("DESC "); sb.Append("INDEX ").Append(_commonUtils.QuoteSqlName(ukname)).Append(" ON ").Append(_commonUtils.QuoteSqlName(tbname)).Append("("); foreach (var tbcol in uk.Columns) { sb.Append(_commonUtils.QuoteSqlName(tbcol.Column.Attribute.Name)); - if (tbcol.IsDesc) sb.Append(" DESC"); + //if (tbcol.IsDesc) sb.Append(" DESC"); sb.Append(", "); } sb.Remove(sb.Length - 2, 2).Append(");\r\n");