Closed RicardoHWu closed 1 year ago
字典设置 null 是什么结果
刚才检查过。
所有驱动处理 AddslashesProcessParam、GetNoneParamaterSqlValue 都没有处理 DBNull.Value 的情况
建议用 c# null 表示该值。
刚才检查过。
所有驱动处理 AddslashesProcessParam、GetNoneParamaterSqlValue 都没有处理 DBNull.Value 的情况
建议用 c# null 表示该值。
请问有自定义这种转换处理的方法,或者设置以字典方式进行select时,结果的空值以null而不是DBNull存储么?就像我文中所说,目前的情况是使用FreeSql从postgresql中以字典类获取数据再直接写入mdb文件,若pg库中为null,则返回的字典中的值为DBNull,使得FreeSql拼接sql时会以‘’而不是null进行处理
可以考虑写入前物理一遍判断 DBNull.Value,这样解决问题会比较简单一些。
AOP 也可以统一处理 AuditValue:
fsql.Aop.AuditValue += (_, e) =>
{
if (e.Object is Dictionary<string, object> dict)
{
foreach(var key in dict.Keys)
{
var val = dict[key];
if (val == DBNull.Value) dict[key] = null;
}
e.ObjectAuditBreak = true;
}
};
aop方法可行,dict的遍历代码需要修改,不然会报集合已被修改,可能无法操作枚举类型的错误
client.Aop.AuditValue += (s, e) => {
if (e.Object is Dictionary<string, object> dict) {
string[] keyArray = dict.Keys.ToArray();
foreach (string key in keyArray) {
if (DBNull.Value.Equals(dict[key])) {
dict[key] = null;
}
}
e.ObjectAuditBreak = true;
}
};
但个人还是建议在框架代码中加入DBNull的处理,毕竟DBNull代表的是数据库中是空值,如果通过拼接sql而非sql预编译执行sql时,将DBNull转为''的处理明显是不合理的。同时框架本身也有对值做遍历处理,若再添加一层遍历也对效率有影响。
3.2.683 处理该问题
更新v3.2.683-preview20221118版本后,如果字典中存在多个DBNull.Value,将会报如下错误
System.InvalidOperationException: 集合已修改;可能无法执行枚举操作。
在 System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
在 System.Collections.Generic.Dictionary`2.KeyCollection.Enumerator.MoveNext()
在 FreeSqlGlobalExtensions.LocalReplaceDictDBNullValue(Dictionary`2 dict) 位置 C:\Users\28810\Desktop\github\FreeSql\FreeSql\Extensions\FreeSqlGlobalExtensions.cs:行号 899
在 FreeSqlGlobalExtensions.InsertDict(IFreeSql freesql, Dictionary`2 source) 位置 C:\Users\28810\Desktop\github\FreeSql\FreeSql\Extensions\FreeSqlGlobalExtensions.cs:行号 879
是否应该放在驱动的 AddslashesProcessParam、GetNoneParamaterSqlValue处理,而非处理前遍历字典进行处理更合理?
static void LocalReplaceDictDBNullValue(Dictionary<string, object> dict)
{
if (dict == null) return;
var keys = dict.Keys;
foreach (var key in keys)
{
var val = dict[key];
if (val == DBNull.Value) dict[key] = null;
}
}
修改成这样了,今天会发布 3.2.683。
AddslashesProcessParam、GetNoneParamaterSqlValue 因为大多数是基于强实体类型,没有 DBNull.Value 的需求,目前针对 InsertDict/UpdateDict/DeleteDict 作处理成本比较低,也算合理。
目前这块是扩展方法的形式存在,不属于 interface,能在边缘上实现最好。
更新v3.2.683版本后,多个DBNull.Value时,依旧报改错误
System.InvalidOperationException: 集合已修改;可能无法执行枚举操作。
在 System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)
在 System.Collections.Generic.Dictionary`2.KeyCollection.Enumerator.MoveNext()
在 FreeSqlGlobalExtensions.LocalReplaceDictDBNullValue(Dictionary`2 dict) 位置 C:\Users\28810\Desktop\github\FreeSql\FreeSql\Extensions\FreeSqlGlobalExtensions.cs:行号 900
在 FreeSqlGlobalExtensions.InsertDict(IFreeSql freesql, IEnumerable`1 source) 位置 C:\Users\28810\Desktop\github\FreeSql\FreeSql\Extensions\FreeSqlGlobalExtensions.cs:行号 891
应该不能使用键集合的引用传递进行字典值的遍历修改吧?
并且由于LocalReplaceDictDBNullValue方法先于AuditValue方法调用,v3.2.683版本无法通过AOP手动处理DBNull的情况
AuditValue 是683版本发布前的解决方法,不冲突
683版本的LocalReplaceDictDBNullValue方法依旧存在多个DBNull.Value时报集合已修改;可能无法执行枚举操作
的问题,加上需要解决https://github.com/dotnetcore/FreeSql/issues/1332 的Odbc问题,由于683版本的odbc驱动依赖683版本的Freesql,目前解决方法是将整体版本回退到3.2.683-preview20221115,使用AuditValue处理
.net framework版本是4.7.2,不确定是否是因为.net框架不一致,所以作者的开发环境并没有报错
请提供一个测试 demo,.net 4.7.2 的
这是测试demo,基于683版本的Freesql和32位access的odbc驱动,使用nunit作为单元测试框架 FreeSqlTest.zip
谢谢反馈,已修复发布 3.2.684-preview20221130
使用freesql以字典格式查询数据时,库中空值将以DBNull而非null的格式存储到字典中,再将数据以InsertDict方式插入以MsAccess驱动或Odbc驱动连接的mdb数据库时,数据将转换为''而非null的格式拼接成sql,若相应的字段不为文本类型将导致报错 查询结果空值返回DBNull而不是null MsAccess驱动或Odbc驱动使用字典插入mdb文件时DBNull将转为'' 而非null
初步判断是OdbcAdo/MsAccessAdo的AddslashesProcessParam方法未对DBNull做判断处理导致,但不确定时候还有其他地方需要修改。
使用的FreeSql、DbContext、Respository、Provider.Odbc版本均为3.2.683-preview20221115,.net framework版本4.5