Entity Framework MySQL中DbGeometry无法从数据库读取的问题
我遇到了一个奇怪的问题:我定义了包含DbGeometry类型字段的实体类,数据能成功保存到MySQL数据库,但从数据库读取时这个字段始终是null,其他字段都正常读取。
相关代码与环境
我的实体类定义:
public partial class UserPosition { // 其他字段... public DbGeometry Position { get; set; } // 其他字段... }
保存数据的代码:
var pos = new UserPosition { // 其他字段赋值... Position = GeographyHelper.CreatePoint(request.Latitude, request.Longitude), // 其他字段赋值... }; db.UserPositions.Add(pos); db.SaveChanges();
GeographyHelper.CreatePoint方法实现:
/// <summary> /// Creates a DbGeometry point from latitude and longitude values /// </summary> /// <param name="latitude"></param> /// <param name="longitude"></param> /// <returns></returns> public static DbGeometry CreatePoint(double latitude, double longitude) { var text = string.Format(CultureInfo.InvariantCulture.NumberFormat, "POINT({0} {1})", longitude, latitude); // 4326 is most common coordinate system used by GPS/Maps return DbGeometry.PointFromText(text, 4326); }
数据保存到数据库后,对应字段的值是POINT (19.038934 47.531),但执行读取代码时:
var rec = db.UserPositions.FirstOrDefault();
返回的记录ID匹配,其他字段正常,但Position字段为null。
环境信息:Visual Studio 2015,.NET 4.5.2,EntityFramework 6.2.0,MySql.Data.Entity.EF6 6.9.12,MySQL数据库版本5.6.15。
原因分析
这个问题主要是因为MySQL的EF6驱动(MySql.Data.Entity.EF6)对空间类型的支持需要额外配置,默认情况下可能没有正确启用空间类型的映射和读取逻辑。另外你使用的驱动版本6.9.12比较老旧,存在一些空间类型处理的bug。
解决步骤
1. 确保数据库列类型正确
首先确认你的UserPosition表中Position列的类型是POINT(你已经成功保存数据,这一步大概率没问题,但可以再检查一下)。
2. 在DbContext中配置空间类型映射
在你的DbContext的OnModelCreating方法中,显式配置Position字段的数据库列类型,确保EF能正确识别:
protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); // 配置Position字段对应MySQL的POINT类型 modelBuilder.Entity<UserPosition>() .Property(u => u.Position) .HasColumnType("POINT"); }
3. 修改连接字符串,启用空间类型支持
在你的数据库连接字符串中添加Spatial=True参数,告诉驱动启用空间类型的处理:
Server=你的服务器地址;Database=你的数据库名;Uid=用户名;Pwd=密码;Spatial=True;
4. 升级MySQL EF6驱动版本
你当前使用的MySql.Data.Entity.EF6 6.9.12版本比较旧,对空间类型的支持不完善。建议升级到最新的稳定版(比如8.x系列),可以通过NuGet包管理器进行升级:
- 卸载旧的
MySql.Data.Entity.EF6包 - 安装最新版的
MySql.Data.EntityFramework(注意:新版本的包名有所变化,不再是MySql.Data.Entity.EF6)
5. 验证读取逻辑
如果以上步骤都完成后,重新运行读取代码,应该就能正确获取到Position字段的值了。如果还是有问题,可以尝试显式指定加载该字段(虽然对于立即查询来说通常不需要,但可以排除延迟加载的问题):
var rec = db.UserPositions.Select(u => new UserPosition { // 其他字段... Position = u.Position }).FirstOrDefault();
内容的提问来源于stack exchange,提问作者Péter Aradi

