2011-05-05 22 views
9

Estoy usando Dapper para extraer algunas herramientas de prueba de carga que necesitan acceder a una base de datos PostgreSQL. Esta versión particular de PostgreSQL no admite GUID de forma nativa, por lo que los valores GUID se almacenan como cadenas de 32 caracteres. Los valores se convierten en cadenas usando someGuid.ToString("N"), la conversión a Guid se puede hacer usando new Guid(stringValueFromColumn).Cadena de mapa para guid con Dapper

Mi pregunta es ¿cómo consigo que Dapper lea las cuerdas y las convierta de nuevo en Guids?

He intentado modificar el mapeo DbType pero eso no funciona.

+0

Aunque se menciona esta manera prominente en su pregunta, no vi a su mención de que se están usando una base de datos que "no admite GUID de forma nativa". Vale la pena señalar que en las bases de datos que lo hacen, uno puede asignar UNIQUEIDENTIFIER en tSQL (o similar) a Guid en C# ([eg] (https://github.com/StackExchange/dapper-dot-net/issues/447)) – dumbledad

Respuesta

16

Tal vez la forma más sencilla de hacer esto (sin esperar el pulcro) es tener una segunda propiedad:

public Guid Foo {get;set;} 

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

Y en su consulta, alias la columna como FooString.

Por supuesto, esto genera la pregunta: ¿debería apostar el soporte de propiedades privadas para este tipo de cosas? A lo que digo: probablemente.

+0

Bueno, eso es un poco más limpio que piratear en Dapper. Permitir que se establezcan propiedades privadas (o campos) sería genial. –

+0

@Marnix - sí, tengo la intención de agregar esos –

+0

@Marnix - ahora todo existe, por cierto (en fuente - No he desinstalado el paquete nuget) –

2

He pirateado una solución juntos. Por lo que puedo decir, no hay forma de ordenar a Dapper que genere un código de vinculación alternativo para un tipo particular, así que modifiqué el método GetClassDeserializer para forzar el tipo de casilla a cadena si la propiedad es un guid. A continuación reutilicé el código que genera una llamada de constructor para las enumeraciones.

He aquí el fragmento de código modificado (a partir de la línea 761 de rev rf6d62f91f31a.):

// 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]
+0

tipo de coerción es algo que evité deliberadamente, ¿le importaría publicar una solicitud de función en nuestro rastreador de errores para ver si tiene sentido acomodarse, tenga en cuenta que habrá una explosión espectacular si el guid en postgres tiene 31 caracteres de largo. .. –

+0

@Sam - meh, GIGO; personalmente esto no me molestaría enormemente. Y hay prioridad en que L2S hace * algunas * conversiones aquí (incluidas las enumeraciones a través del nombre como cadena). –

+0

@Sam Gracias, he publicado la solicitud de función. –

3

Esta es una vieja pregunta, pero creo que necesita una actualización ya que Dapper ahora es compatible con propiedades privadas, a lo que se ha referido Marc en su respuesta.

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

A continuación, en SQL darle a su columna de ID de un alias para asignar a la propiedad privada y no la propiedad real:

SELECT UserID AS UserIDString FROM....