DotNetNext / SqlSugar

.Net aot ORM Fastest ORM Simple Easy VB.NET Sqlite orm Oracle ORM Mysql Orm postgresql ORm SqlServer oRm 达梦 ORM 人大金仓 ORM 神通ORM C# ORM , C# ORM .NET ORM NET5 ORM .NET6 ORM ClickHouse orm QuestDb ,TDengine ORM,OceanBase orm,GaussDB orm ,Tidb orm Object/Relational Mapping

Home Page:https://www.donet5.com/Home/Doc

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

PostgresSQL 无法映射自定义数据库类型

ZeekoZhu opened this issue · comments

commented

例如 pgvector 提供的 vector 类型,需要通过 pgsql 的 TypeMapping 添加自定义的 handler,但是却无法设置 SugarParameter.CustomDbType 为 null ,从而导致 Npgsql 无法使用自定义类型

image

image

commented

https://www.donet5.com/Home/Doc?typeId=2542 sqlsugar有自定义类型

我的使用场景跟这篇文档有些不同, pgvector 是 pgsql 的一个插件,提供了一个新的数据库类型 vector,我需要将一个 dotnet class 映射到 vector 类型。创建 ISugarDataConverter 是必须的,否则 SqlSugar 无法正确设置参数类型,默认是 String,我需要将其设置为 vector 类型。

除了参数外,在读取数据的时候也需要配置 Npgsql 的 TypeHandler,否则 Npgsql 驱动将无法识别 vector 类型。

但是现在问题出现了,在 ISugarDataConverter.ParameterConverter 中,必须要将 CustomDbType 设置成一个非 Null 的值,否则最终生成的 NpgsqlParamter.NpgsqlDbType 将是 string。但是 Npgsql 的自定义 TypeHandler 只会处理 NpgsqlDbType 字段为 Null 的参数。

我查阅了 SqlSugar 的代码,并没有办法将最终生成的 NpgsqlParamter.NpgsqlDbType 设置成 null 。

image

你研究一下原生怎么写的,这个东西不可能等于 NULL

commented

找到了一个方法:

    var parameter = new SugarParameter(name, null)
    {
      DbType = DbType.Object, // 调用 NpgsqlParameter.DbType 的 setter 将 NpgsqlDbType  设置成 null
      Value = value // 重新设置 Value,避免 SqlSugar 自动将 value 转换成 JSON string
    };

能用就行

commented
    var other = new PgVector(new[] { 1.0f, 2.0f, 3.0f });
    var item = _db.Queryable<VectorItem>().Select(x => VectorOperator.Distance(x.Vector, other)).First();

我发现在查询的时候,Expression 中的参数无法被 SqlSugar 的自定义类型 Converter 处理,导致 SugarParameter 的 DbType 被设置为 AsciiString

commented

类似的情况还有下面这种:

    var item = _db.Queryable<VectorItem>()
      .Select(x => SqlFunc.AggregateAvg(x.Vector))
      .First();

报错:

System.ArgumentNullException : Value cannot be null. (Parameter 'con')
   at System.Reflection.Emit.DynamicILGenerator.Emit(OpCode opcode, ConstructorInfo con)
   at SqlSugar.IDataReaderEntityBuilder`1.CreateBuilder(Type type)
   at SqlSugar.DbBindAccessory.<>c__DisplayClass4_0`1.<GetEntityList>b__0()
   at SqlSugar.ReflectionInoCore`1.GetOrCreate(String cacheKey, Func`1 create)
   at SqlSugar.ReflectionInoCacheService.GetOrCreate[V](String cacheKey, Func`1 create, Int32 cacheDurationInSeconds)
   at SqlSugar.DbBindAccessory.GetEntityList[T](SqlSugarProvider context, IDataReader dataReader)
   at SqlSugar.DbBindProvider.DataReaderToList[T](Type type, IDataReader dataReader)
   at SqlSugar.QueryableProvider`1.GetData[TResult](Boolean isComplexModel, Type entityType, IDataReader dataReader)
   at SqlSugar.QueryableProvider`1.GetData[TResult](KeyValuePair`2 sqlObj)
   at SqlSugar.QueryableProvider`1._ToList[TResult]()
   at SqlSugar.QueryableProvider`1.ToList()
   at SqlSugar.QueryableProvider`1.First()

我推测 SqlSugar 将我的自定义类型 PgVector 当作实体类型读取了,可是我已经在 Npgsql 设置过自定义类型了,这时 DataReader 返回的应该就是 PgVector 实例,不需要 SqlSugar 转换了

commented

我推测 SqlSugar 将我的自定义类型 PgVector 当作实体类型读取了,可是我已经在 Npgsql 设置过自定义类型了,这时 DataReader 返回的应该就是 PgVector 实例,不需要 SqlSugar 转换了

尝试使用实体类型作为 Select 的值

    var item = _db.Queryable<VectorItem>()
      .Select(x => new VectorItem { Vector = SqlFunc.AggregateAvg(x.Vector), Id = 0 })
      .First();

结果生成的 sql 中缺少了聚合列。。。

image

单个字段识别不了自定义类型
new class(){ 有特性的属性=SqlFunc.AggregateAvg(x.Vector)}

这样就能识别

我来验证一下

var item = _db.Queryable<VectorItem>()
  .Select(x => new VectorItem { Vector = SqlFunc.AggregateAvg(x.Vector), Id = 0 })
  .First();

你这个应该把ID去掉,如果2个字段需要GROUP BY

commented

感谢,已经没有问题了