【问题标题】:dapper.fastcrud doesn't mapped geometry data from postgresqldapper.fastcrud 没有映射来自 postgresql 的几何数据
【发布时间】:2019-03-11 22:28:11
【问题描述】:

我在 Postgresql 中有一个空间数据。例如表planet_osm_point有2个属性:

CREATE TABLE public.planet_osm_point
(
    osm_id bigint,
    way geometry(Point,3857)
)

如果我使用简洁的 CRUD 操作一切正常。但是,如果我使用 Dapper.fastCRUD,那么几何的“方式”属性始终为空

类 OsmPoint:

using NetTopologySuite.Geometries;
using System.ComponentModel.DataAnnotations.Schema; 

namespace DapperTest
{
    [Table("planet_osm_point")]
    public class OsmPoint
    {
        [Column("osm_id")]
        public long OsmId { get; set; }

        [Column("way")]
        public Point Way { get; set; }
    }
}

如果我使用 Dapper,那么我会收到 Way 属性有几何坐标:

using (NpgsqlConnection conn = new NpgsqlConnection(_connectionString))
{
    conn.Open();
    conn.TypeMapper.UseNetTopologySuite();
    var result = conn.Query<OsmPoint>("SELECT * FROM planet_osm_point LIMIT 5000").ToList();
    return result;
}

但是如果我使用 Dapper.fastCRUD 那么 Way 总是为 null

using (NpgsqlConnection conn = new NpgsqlConnection(_connectionString))
{
    conn.Open();
    conn.TypeMapper.UseNetTopologySuite();
    var result = conn.Find<OsmPoint>(p=>p.Top(5000));
    return result;
}

有人知道如何让 Dapper.fastCRUD 处理几何数据吗?

【问题讨论】:

    标签: postgresql dapper spatial dapper-fastcrud


    【解决方案1】:

    首先为 Geometry 类型创建 TypeHandler,如下所示:

    public class GeometryTypeMapper : SqlMapper.TypeHandler<Geometry>
    {
        public override void SetValue(IDbDataParameter parameter, Geometry value)
        {
            if (parameter is NpgsqlParameter npgsqlParameter)
            {
                npgsqlParameter.NpgsqlDbType = NpgsqlDbType.Geometry;
                npgsqlParameter.NpgsqlValue = value;
            }
            else
            {
                throw new ArgumentException();
            }
        }
    
        public override Geometry Parse(object value)
        {
            if (value is Geometry geometry)
            {
                return geometry;
            }
    
            throw new ArgumentException();
        }
    }
    

    添加类型处理程序:

    SqlMapper.AddTypeHandler(new GeometryTypeMapper());
    

    在 FastCURD 查询前设置属性:

    OrmConfiguration.GetDefaultEntityMapping<OsmPoint>().SetProperty(p => p.way, prop => prop.SetDatabaseColumnName("way"));
    

    【讨论】:

    • 是的,Dapper 需要此代码来映射几何数据。但是 Dapper.FastCRUD 忽略了构建查询的几何属性。在这种情况下,FastCRUD 返回查询:从“planet_osm_point”中选择“osm_id”。此查询不包含“方式”属性。
    • 默认 Dapper.FastCURD 将忽略几何属性,因此您将获得几何属性的空值,因此您必须在查询或更新之前通过 SetProperty 重新定义它。
    • 维基有一篇文章link。但是我看到的太晚了。一切都在那里解释=)
    【解决方案2】:

    Dapper.FastCRUD 默认只使用简单的 sql 类型来构建查询。 你可以在 Dapper.FastCrud.Configuration.OrmConventions.cs 中看到它:

    public virtual IEnumerable<PropertyDescriptor> GetEntityProperties(Type entityType)
    {
        return TypeDescriptor.GetProperties(entityType)
            .OfType<PropertyDescriptor>()
            .Where(propDesc => 
                !propDesc.Attributes.OfType<NotMappedAttribute>().Any()
                && !propDesc.IsReadOnly 
                && propDesc.Attributes.OfType<EditableAttribute>().All(editableAttr => editableAttr.AllowEdit)
                && this.IsSimpleSqlType(propDesc.PropertyType));
    }
    

    我重写了 IsSimpleSqlType(Type propertyType) 方法:

    public class GeometryConvention: OrmConventions
    {
        protected override bool IsSimpleSqlType(Type propertyType)
        {
            var res = base.IsSimpleSqlType(propertyType) || propertyType.BaseType != null && propertyType.BaseType.Name.StartsWith("geometry", StringComparison.OrdinalIgnoreCase);
            return res;
        }
    }
    

    注册自定义约定:

    OrmConfiguration.Conventions = new GeometryConvention();
    

    并使用自定义 GeometryTypeMapper,例如 Long Ngô Thành 答案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-01-22
      • 2021-10-01
      • 2011-02-02
      • 2020-11-01
      • 2022-12-11
      • 1970-01-01
      • 1970-01-01
      • 2020-06-27
      相关资源
      最近更新 更多