Usando Dapper con SQL Spatial Types como parámetro

dapper orm spatial sql-server-2008

Pregunta

Tengo un sistema que básicamente tiene que hacer una consulta como esta:

SELECT * FROM MyTable WHERE @parameter.STIntersects(MyGeometryColumn)

Esto es bastante simple de hacer al usar parámetros de SQL vainilla, solo tiene que crear su parámetro de una manera no típica (donde la variable del constructor es un SqlGeometryBuilder que yo uso para crear un rectángulo):

command.Parameters.Add(new SqlParameter
{
    UdtTypeName = "geometry",
    Value = builder.ConstructedGeometry,
    ParameterName = "@paremeter"
});

Ahora, cuando trato de hacer esto usando dapper, me da un error que no puede entender cómo usar esto como un parámetro. ¿Alguien que tiene esto funcionando, o algún indicador sobre cómo habilitar esto? Tengo una solución alternativa, pero eso implica el uso de la representación de cadena y convertir eso a un tipo de geometría en mi consulta SQL. Realmente no quiero eso.

Para responder el comentario, el error que obtengo es 'El parámetro miembro de tipo Microsoft.SqlServer.Types.SqlGeometry no se puede usar como valor de parámetro'. En otras palabras, dapper no sabe cómo tratar con un objeto SqlGeometry como parámetro.

Respuesta aceptada

La clave para implementar parámetros específicos de DB raros y maravillosos se reduce a SqlMapper.IDynamicParameters

Esta interfaz simple tiene un solo punto final:

public interface IDynamicParameters
{
    void AddParameters(IDbCommand command);
}

Dapper ya tiene una implementación genérica de DB de esta interfaz llamada: DynamicParameters que le permite manejar los valores de salida y retorno.

Para emular estas cosas espaciales, probaría algo como:

public class SpatialParam : SqlMapper.IDynamicParameters
{
    string name; 
    object val;

    public SpatialParam(string name, object val)
    {
       this.name = name; 
       this.val = val;
    }

    public void AddParameters(IDbCommand command, SqlMapper.Identity identity)
    {
       var sqlCommand = (SqlCommand)command;
       sqlCommand.Parameters.Add(new SqlParameter
       {
          UdtTypeName = "geometry",
          Value = val,
          ParameterName = name
       });
    }
}

Uso:

cnn.Query("SELECT * FROM MyTable WHERE @parameter.STIntersects(MyGeometryColumn)",
  new SpatialParam("@parameter", builder.ConstructedGeometry));

Esta implementación simple de la interfaz maneja solo un único parámetro, pero se puede extender fácilmente para manejar múltiples params, ya sea al pasar desde el constructor o al agregar un método auxiliar AddParameter.


Respuesta experta

  • Dapper.EntityFramework 1.26 tiene soporte para DbGeography
  • Dapper 1.32 tiene soporte incorporado para SqlGeography
  • Dapper 1.33 tiene soporte incorporado para SqlGeometry
  • Dapper.EntityFramework 1.33 tiene soporte incorporado para DbGeometry
  • Dapper 1.34 tiene soporte incorporado para SqlHierarchyId

Entonces con las últimas bibliotecas; simplemente debería funcionar.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué