1.关于ABP使用postgis配置流程。首先在Acme.BookStore.EntityFrameworkCore项目中安装Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite
2.安装好之后在Domain层创建一个使用地理几何的类。
[Table("ChinaGis")]
public class ChinaGis : Entity<string>
{
[Column("Id")]
public override string Id { get; protected set; }
public string name { get; set; }
public Geometry geom { get; set; }
}
3.将实体添加到上下文,然后再程序包管理器使用迁移命令Add-Migration fss,此时会报错:The property 'gis_osm_railways_free_1.geom' is of type 'Geometry' which is not supported by the current database provider. Either change the property CLR type, or ignore the property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
造成这个错误的原因是没有启用PostGis扩展,在BookStoreDbContextFactory里面,启用一下就可以了。
var builder = new DbContextOptionsBuilder<BookStoreDbContext>()
.UseNpgsql(configuration.GetConnectionString("Default"),
x=>x.UseNetTopologySuite());
BookStoreDbContextFactory这个主要是在使用命令行迁移的时候使用的,如果使用Acme.BookStore.DbMigrator进行生成,需要在BookStoreEntityFrameworkCoreModule里面启用一下UseNetTopologySuite
Configure<AbpDbContextOptions>(options =>
{
/* The main point to change your DBMS.
* See also BookStoreMigrationsDbContextFactory for EF Core tooling. */
options.UseNpgsql(x=>x.UseNetTopologySuite());
});
4.在上面配置都做完之后,在使用Add-Migration fss,构建成功之后,使用命令Update-Databse初始化数据库,也可以直接运行Acme.BookStore.DbMigrator程序来生成,都可以,成功之后就可以在数据库中看到ChinaGis 表了。
TIP:在运行Update-Databse如果报错,Npgsql.PostgresException (0x80004005): 42704: 类型 "geometry" 不存在,,报错原因,是因为数据库中没有启用postgis扩展,解决方法:在OnModelCreating方法里面增加builder.HasPostgresExtension("postgis");,启用postgis扩展。
5.在上述所有操作都完成之后,在Domain层ChinaGis下面运行abphelper generate crud ChinaGis -d path,执行成功之后,删除生成的多余项,先不用关注其他操作,只看Application层。在这里要注意一下,无论是添加还是查询,在自动生成的dao里面都不可以有Geometry类型的,否则,会报错,报如下错误,可能是接口返回的原因吧。查询的时候将Geometry更改为string类型,程序可以直接映射
"message": "对不起,在处理你的请求期间,产生了一个服务器内部错误!",
6.注意,在创建数据的时候,dto里面Geometry不能直接和和数据库里面直接映射,需要进行转换。
下面是添加和查询的代码。
public async override Task<ChinaGisDto> CreateAsync(CreateUpdateChinaGisDto input)
{
await CheckCreatePolicyAsync().ConfigureAwait(continueOnCapturedContext: false);
ChinaGis entity = await MapToEntityAsync(input).ConfigureAwait(continueOnCapturedContext: false);
TryToSetTenantId(entity);
Coordinate[] points =
{
new Coordinate(124.3786722,40.1239114),
new Coordinate(124.3782163,40.124215)
};
LineString[] lineString = { new LineString(points) };
MultiLineString multiLineString = new MultiLineString(lineString);
Geometry geometry = multiLineString;
entity.geom = multiLineString;
await Repository.InsertAsync(entity, autoSave: true).ConfigureAwait(continueOnCapturedContext: false);
return await MapToGetOutputDtoAsync(entity).ConfigureAwait(continueOnCapturedContext: false);
}
public async override Task<PagedResultDto<ChinaGisDto>> GetListAsync(PagedAndSortedResultRequestDto input)
{
try
{
await CheckGetListPolicyAsync();
var query = await CreateFilteredQueryAsync(input);
var totalCount = await AsyncExecuter.CountAsync(query);
query = ApplySorting(query, input);
query = ApplyPaging(query, input);
var entities = await AsyncExecuter.ToListAsync(query);
var entityDtos = await MapToGetListOutputDtosAsync(entities);
return new PagedResultDto<ChinaGisDto>(
totalCount,
entityDtos
);
}
catch (Exception ex)
{
throw ex;
}
}
7.关于使用ef操作postgis,我更建议直接使用sql的方式,这种方式更简单便捷一些,在abphelper生成的数据上下文中,添加sql语句
public class ChinaGisRepository : EfCoreRepository<BookStoreDbContext, ChinaGis, string>, IChinaGisRepository
{
public ChinaGisRepository(IDbContextProvider<BookStoreDbContext> dbContextProvider) : base(dbContextProvider)
{
}
public async Task<List<ChinaGis>> GetFdd()
{
string sql = "select *from public.ChinaGis";
var dbContext = await GetDbContextAsync();
return await dbContext.Set<ChinaGis>().FromSqlRaw(sql).ToListAsync();
}
}