简体   繁体   English

Map 用 Dapper 引导字符串

[英]Map string to guid with Dapper

I'm using Dapper to hammer out some load testing tools that need to access a PostgreSQL database.我正在使用 Dapper 敲定一些需要访问 PostgreSQL 数据库的负载测试工具。 This particular version of PostgreSQL does not support GUIDs natively, so GUID values are stored as 32 character strings.此特定版本的 PostgreSQL 本身不支持 GUID,因此 GUID 值存储为 32 个字符串。 The values are converted to strings using someGuid.ToString("N") , conversion back to Guid can be done using new Guid(stringValueFromColumn) .使用someGuid.ToString("N")将值转换为字符串,可以使用new Guid(stringValueFromColumn)将值转换回 Guid。

My question is how do I get Dapper to read the strings and convert them back to Guids?我的问题是如何让 Dapper 读取字符串并将它们转换回 Guid?

I tried modifying the DbType mapping but that doesn't work.我尝试修改 DbType 映射,但这不起作用。

I'm using MySql but it has the same problem since I store the Guid as a string.我正在使用 MySql 但它有同样的问题,因为我将 Guid 存储为字符串。 To fix the mapping without having to alias the column i used the following:为了修复映射而不必为列设置别名,我使用了以下内容:

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);
    }
}

And in my Startup.cs:在我的 Startup.cs 中:

public void ConfigureServices(IServiceCollection services)
    {
        SqlMapper.AddTypeHandler(new MySqlGuidTypeHandler());
        SqlMapper.RemoveTypeMap(typeof(Guid));
        SqlMapper.RemoveTypeMap(typeof(Guid?));
    }

Perhaps the simplest way to do this (without waiting on dapper) is to have a second property:也许最简单的方法(无需等待 dapper)是拥有第二个属性:

public Guid Foo {get;set;}

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

And in your query, alias the column as FooString .在您的查询中,将该列别名为FooString

Of course, then this prompts the question: should dapper support private properties for this type of thing?当然,那么这就提出了一个问题:dapper 是否应该支持这种类型的东西的私有属性? To which I say: probably.我说:可能。

This is an old question but I feel it needs updating as Dapper now supports private properties, which Marc referenced to in his answer .这是一个老问题,但我觉得它需要更新,因为 Dapper 现在支持私有属性,Marc 在他的回答中提到了这些属性。

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

Then in SQL give your ID column an alias to map it to the private property and not the actual property:然后在 SQL 给你的 ID 列一个别名 map 它是私有财产而不是实际财产:

SELECT UserID AS UserIDString FROM....

It looks like there is UUID type in PostgreSQL already.看起来 PostgreSQL 中已经有 UUID 类型了。 But @Cpt.Ohlund's solution is still great for MySQL/MariaDB in 2020.但是@Cpt.Ohlund 的解决方案对于 2020 年的 MySQL/MariaDB 来说仍然很棒。

But the solution might cause problems itself.但是解决方案本身可能会导致问题。

When VARCHAR(36) is used for System.Guid the following exception is thrown:VARCHAR(36)用于System.Guid时,将引发以下异常:

System.InvalidCastException: Invalid cast from 'System.String' to 'System.Guid'. System.InvalidCastException:从“System.String”到“System.Guid”的无效转换。

@Cpt.Ohlund's solution makes it work. @Cpt.Ohlund 的解决方案使它起作用。

But if the column is CHAR(36) then it is mapped to System.Guid automatically.但如果该列是CHAR(36) ,那么它会自动映射到System.Guid And if @Cpt:Ohlund's solution is applied there will be another exception:如果应用@Cpt:Ohlund 的解决方案,将会有另一个例外:

System.InvalidCastException: Unable to cast object of type 'System.Guid' to type 'System.String'. System.InvalidCastException:无法将“System.Guid”类型的 object 转换为“System.String”类型。

The exception is caused by an instance System.Guid passed to Parse(object value) instead of a string.该异常是由传递给Parse(object value)而不是字符串的实例System.Guid引起的。


So the simple answer is to use CHAR(36) in MySQL and MariaDB and it will just work.所以简单的答案是在 MySQL 和 MariaDB 中使用CHAR(36)并且它会起作用。

But if you need to handle any string type of the column you have to use an improved @Cpt.Ohlund's solution:但是,如果您需要处理列的任何字符串类型,则必须使用改进的@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);
    }
}

And register it using SqlMapper.AddTypeHandler() .并使用SqlMapper.AddTypeHandler()注册它。

I hacked a solution together.我一起破解了一个解决方案。 As far as I can tell, there is no way to instruct Dapper to generate alternate binding code for a particular type so I modified the GetClassDeserializer method to force the unbox type to string if the property is a guid.据我所知,没有办法指示 Dapper 为特定类型生成备用绑定代码,因此我修改了GetClassDeserializer方法,如果属性是 guid,则强制拆箱类型为字符串。 Next I re-used the code that generates a constructor call for enums.接下来,我重新使用了为枚举生成构造函数调用的代码。

Here's the modified code snippet (starting at line 761 of rev. rf6d62f91f31a):这是修改后的代码片段(从 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]

I hope that can help.我希望这能有所帮助。

I didn't have to use alias in my query.我不必在查询中使用别名。 What I did:我做了什么:

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

    public string Id
    {
        get; set; 
    }
}

And in your table the type as varchar在您的表格中,类型为 varchar

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM