使用Dapper查询空间数据

5
我找到了一些相关的问题,但是作者放弃了,并使用存储过程来进行“映射”。
这实际上是一个续问,来源于这里

模型

public class Store
{
    public int Id { get; private set; }
    public string Name { get; set; }
    public string Address { get; set; }
    public DbGeography Location { get; set; }
}

查询

using (SqlConnection conn = SqlHelper.GetOpenConnection())
{
    const string sql = "Select * from Stores";
    return conn.Query<Store>(sql, new { Tenant_Id = tenantId });
}

Dapper无法理解空间数据,并且正如许多人所说,作者最初的意图并不是支持供应商特定的实现。但是扩展Query<T>支持的文档很难找到。


并不是说这很难找,而是它不是一个功能。它可能是,但需要进行范围界定、设计、编写、测试、文档化和部署。我非常欢迎想法/贡献... - Marc Gravell
是的。而且似乎Dapper可能只需采用“希望它能工作”的方法来处理任何它不认识的内容 - 并将其作为值添加而无需进行任何其他处理(或从GetValue中转换,然后假设它会起作用)。我愿意研究一下这个问题,但是:这不是它今天所做的事情。 - Marc Gravell
请问,你能指导我如何让这个工作吗?有没有自定义解析的接口? - Lee Gary
我刚做了一个快速测试,结果是:采用“希望它能工作”的方法行不通:“不存在从对象类型System.Data.Entity.Spatial.DbGeography到已知托管提供程序本机类型的映射”(来自于SqlCommand/TdsParser)。目前没有用于自定义解析的接口:这需要进行范围、设计、编写和测试等一系列工作。 - Marc Gravell
这就引出了一个问题:如果这是原始的 ADO.NET,你会怎么做才能让它工作?您会使用 Microsoft.SqlServer.Types.dll 中的 SqlGeography 吗? - Marc Gravell
显示剩余4条评论
1个回答

8
我曾经对这个进行了探索,以下测试已通过:
class HazGeo
{
    public int Id { get;set; }
    public DbGeography Geo { get; set; }
}
public void DBGeography_SO24405645_SO24402424()
{
    global::Dapper.SqlMapper.AddTypeHandler(typeof(DbGeography), new GeographyMapper());
    connection.Execute("create table #Geo (id int, geo geography)");

    var obj = new HazGeo
    {
        Id = 1,
        Geo = DbGeography.LineFromText("LINESTRING(-122.360 47.656, -122.343 47.656 )", 4326)
    };
    connection.Execute("insert #Geo(id, geo) values (@Id, @Geo)", obj);
    var row = connection.Query<HazGeo>("select * from #Geo where id=1").SingleOrDefault();
    row.IsNotNull();
    row.Id.IsEqualTo(1);
    row.Geo.IsNotNull();
}

class GeographyMapper : Dapper.SqlMapper.TypeHandler<DbGeography>
{
    public override void SetValue(IDbDataParameter parameter, DbGeography value)
    {
        parameter.Value = value == null ? (object)DBNull.Value : (object)SqlGeography.Parse(value.AsText());
        ((SqlParameter)parameter).UdtTypeName = "GEOGRAPHY";
    }
    public override DbGeography Parse(object value)
    {
        return (value == null || value is DBNull) ? null : DbGeography.FromText(value.ToString());
    }
}

看起来可行,但我还没有仔细检查每一个细节。你可以在本地尝试这个提交 - 我很乐意听取反馈。


在我的环境中它完美运作,只有一个简单的问题,我在global.asax中应用程序启动时“注册”了typehandler,这是一个好的放置位置吗? - Lee Gary
提高此解决方案的性能的一种方法是使用众所周知的二进制格式来转换SqlGeography和DbGeography,而不是使用众所周知的文本格式,请参见https://dev59.com/QmUp5IYBdhLWcg3wtZI0#29200641以获取示例。 - Serge Belov
@Serge 很好,我已经将其拉入 "dapper" 中:https://github.com/StackExchange/dapper-dot-net/commit/8ab859c7092e94dcf89c50c08cc317e4539d567a - Marc Gravell
这真的救了我的命。再次感谢Gravell先生! - Pure.Krome

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接