21

我正在使用 Dapper 敲定一些需要访问 PostgreSQL 数据库的负载测试工具。这个特定版本的 PostgreSQL 本身不支持 GUID,因此 GUID 值存储为 32 个字符串。使用 将值转换为字符串someGuid.ToString("N"),可以使用 转换回 Guid new Guid(stringValueFromColumn)

我的问题是如何让 Dapper 读取字符串并将它们转换回 Guid?

我尝试修改 DbType 映射,但这不起作用。

4

6 回答 6

58

我正在使用 MySql,但它也有同样的问题,因为我将 Guid 存储为字符串。为了修复映射而不必为列设置别名,我使用了以下内容:

public class MySqlGuidTypeHandler : SqlMapper.TypeHandler<Guid>
{
    public override void SetValue(IDbDataParameter parameter, Guid guid)
    {
        parameter.Value = guid.ToString();
    }

    public override Guid Parse(object value)
    {
        return new Guid((string)value);
    }
}

在我的 Startup.cs 中:

public void ConfigureServices(IServiceCollection services)
    {
        SqlMapper.AddTypeHandler(new MySqlGuidTypeHandler());
        SqlMapper.RemoveTypeMap(typeof(Guid));
        SqlMapper.RemoveTypeMap(typeof(Guid?));
    }
于 2018-09-13T18:40:07.743 回答
26

也许最简单的方法(无需等待 dapper)是拥有第二个属性:

public Guid Foo {get;set;}

public string FooString {
    get { return Foo.ToString("N"); }
    set { Foo = new Guid(value); }
}

在您的查询中,将该列别名为FooString.

当然,那么这就提出了一个问题:dapper 是否应该支持这种类型的东西的私有属性?我说:可能。

于 2011-05-07T11:47:14.180 回答
5

这是一个老问题,但我觉得它需要更新,因为 Dapper 现在支持私有属性,Marc 在他的回答中提到了这些属性。

private String UserIDString { get; set; }
public Guid UserID
{
    get
    {
        return new Guid(UserIDString);
    }
    private set
    {
        UserID = value;
    }
}

然后在 SQL 中为您的 ID 列提供一个别名,以将其映射到私有属性而不是实际属性:

SELECT UserID AS UserIDString FROM....
于 2015-07-24T09:56:50.777 回答
5

看起来 PostgreSQL 中已经有 UUID 类型了。但是@Cpt.Ohlund 的解决方案对于 2020 年的 MySQL/MariaDB 来说仍然很棒。

但是解决方案本身可能会导致问题。

VARCHAR(36)用于System.Guid抛出以下异常时:

System.InvalidCastException:从“System.String”到“System.Guid”的无效转换。

@Cpt.Ohlund 的解决方案使它起作用。

但是,如果该列是,CHAR(36)那么它会System.Guid自动映射到!如果应用@Cpt.Ohlund 的解决方案,将会有另一个例外:

System.InvalidCastException:无法将“System.Guid”类型的对象转换为“System.String”类型。

异常是由System.Guid传递给的实例Parse(object value)而不是字符串引起的。


所以简单的答案是CHAR(36)在 MySQL 和 MariaDB 中使用它,它就可以工作。

但是,如果您需要处理列的任何字符串类型,则必须使用改进的@Cpt.Ohlund 解决方案:

public class MySqlGuidTypeHandler : SqlMapper.TypeHandler<Guid>
{
    public override void SetValue(IDbDataParameter parameter, Guid guid)
    {
        parameter.Value = guid.ToString();
    }

    public override Guid Parse(object value)
    {
        // Dapper may pass a Guid instead of a string
        if (value is Guid)
            return (Guid)value;

        return new Guid((string)value);
    }
}

并使用SqlMapper.AddTypeHandler().

于 2020-05-19T16:14:48.070 回答
2

我一起破解了一个解决方案。据我所知,没有办法指示 Dapper 为特定类型生成备用绑定代码,所以我修改了GetClassDeserializer方法,如果属性是 guid,则强制取消装箱类型为字符串。接下来,我重新使用了为枚举生成构造函数调用的代码。

这是修改后的代码片段(从 rev.rf6d62f91f31a 的第 761 行开始):

// unbox nullable enums as the primitive, i.e. byte etc
  var nullUnderlyingType = Nullable.GetUnderlyingType( item.Info.Type );
  var unboxType = nullUnderlyingType != null && nullUnderlyingType.IsEnum ? nullUnderlyingType : item.Info.Type;
  if( unboxType == typeof(Guid))
  {
    unboxType = typeof (string);
  }
  il.Emit( OpCodes.Unbox_Any, unboxType ); // stack is now [target][target][typed-value]
  if (  ( item.Info.Type == typeof( Guid ) && unboxType == typeof( string ) ) 
        || ( nullUnderlyingType != null && nullUnderlyingType.IsEnum ) )
  {
    il.Emit( OpCodes.Newobj, item.Info.Type.GetConstructor( new[] { nullUnderlyingType ?? unboxType} ) );
  }

  il.Emit( OpCodes.Callvirt, item.Info.Setter ); // stack is now [target]
于 2011-05-06T10:07:47.057 回答
0

我希望这能有所帮助。

我不必在查询中使用别名。我做了什么:

public abstract class Entity
{
    protected Entity()
    {
        Id = Guid.NewGuid().ToString();
    }

    public string Id
    {
        get; set; 
    }
}

在您的表格中,类型为 varchar

于 2020-05-13T00:19:45.287 回答