实体框架核心:此平台不支持类型Udt。 (空间数据 - 地理) [英] Entity Framework Core: Type Udt is not supported on this platform. (Spatial Data - Geography)

查看:334
本文介绍了实体框架核心:此平台不支持类型Udt。 (空间数据 - 地理)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实体框架核心,并绊倒了我从未见过的错误,无法弄明白如何解决它。
我正在使用.net Core Web API 2.0与EntityFramework Core 2.00-preview2-final



这是一个简单的例子,触发错误。 >

(概念:从数据库获取用户的简单端点)



错误:
System.PlatformNotSupportedException:Type Udt不支持此平台。



任何建议?



问题是, m在我的数据库中使用地理位置,但我将其用作我的模型中的字符串,因为实体框架核心不支持空间数据...



任何方式保持这个蛋糕美味而不会摆脱地理,因为这是一个重要的功能?



编辑:查看我的答案目前的解决方案

解决方案

确定这里是我如何解决的:



目的是保持地理位置在实体框架核心(不使用DbGeography)



1)我创建了一个名为Location的结构:

  public struct Location 
{
public double Longitude {get;组; }
public double Latitude {get;组;
}

2)将其添加到您的EF实体模型

  public class User 
{
public Location Location {get;组;
}

3)隐藏在你的modelbuilder中

 保护覆盖void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity< User>()忽略(x =>位置);
}

4)生成迁移(添加迁移迁移名)



5)转到您的迁移文件1231randomnumbers1231_migrationname.cs
并添加以下内容(以这种方式我们创建另一个名为Location的地理类型列),然后更新您的数据库(update-database ):

  migrationBuilder.Sql(@ALTER TABLE [dbo]。[User] ADD [Location] geography NULL 

6)(可选)我创建了一个静态类来更新数据库,如果你有一个位置列在mulple表。

  public static class GeneralDB 
{

public static async Task UpdateLocation(DbContext ctx,string table,Location location,int id)
{
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(en-US);

string query = String.Format(@UPDATE [dbo]。[{0}] SET Location = geography :: STPointFromText('POINT('+ CAST({1} AS VARCHAR(20) )+''+ CAST({2} AS VARCHAR(20))+')',4326)WHERE(ID = {3})
,table.ToLower(),location.Longitude,location.Latitude , ID);
等待ctx.Database.ExecuteSqlCommandAsync(query);
}
public static async任务<位置> GetLocation(DbContext ctx,string table,int id)
{
位置location = new Location();

使用(var command = ctx.Database.GetDbConnection()。CreateCommand())
{
string query = String.Format(SELECT Location.Lat AS Latitude,Location 。长度经度FROM [dbo]。[{0}] WHERE Id = {1}
,table,id);
command.CommandText = query;
ctx.Database.OpenConnection();
使用(var result = command.ExecuteReader())
{
if(result.HasRows)
{
while(await result.ReadAsync())
{
location.Latitude = result.GetDouble(0);
location.Longitude = result.GetDouble(1);
}
}

}
}

返回位置;
}
}

这只适用于EF Core 2.0

  Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(en-US); 

对于EF Core 1.0,您必须找到替换','与'的替代方法。 。一个很好的老式的.Replace()方法可以做这个工作。

  location.Longitude.ToString() ','。')

7)CRUD示例:



7.1:阅读

  public async任务< User> GetByIdAsync(int id)
{
用户user = await ctx.User.AsNoTracking()。SingleOrDefaultAsync(x => x.Id == id);

user.Location = await GeneralDB.GetLocation(ctx,user,id);
返回用户;
}

7.2:创建

  public async任务< User> CreateAsync(User entity)
{

ctx.User.Add(entity);
await ctx.SaveChangesAsync();
等待GeneralDB.UpdateLocation(ctx,user,entity.Location,entity.Id);
返回实体;
}

7.3:更新

  public async任务< User> UpdateAsync(用户实体)
{
ctx.User.Attach(entity);
ctx.Entry< User>(entity).State = EntityState.Modified;
await ctx.SaveChangesAsync();

等待GeneralDB.UpdateLocation(ctx,user,entity.Location,entity.Id);

返回实体;
}


I'm experimenting with entity framework core and stumbled upon an error I've never seen before and can't figure out how to fix it. I'm using .net Core Web API 2.0 with EntityFramework Core 2.00-preview2-final

Here is a simple example that triggers the error.

(concept: simple endpoint to get a user from database)

Error: System.PlatformNotSupportedException: Type Udt is not supported on this platform.

Any suggestions?

The problem is that I'm using geography in my database but I use it as a string in my model, because entity framework core doesn't support spatial data yet...

Any way to keep this cake tasty without getting rid of geography, cause it's an important feature?

Edit : See my answer for current solution

解决方案

Ok here is how I solved it:

The purpose is to keep geography in Entity Framework Core (without using DbGeography)

1) I created a struct called Location:

public struct Location
{
    public double Longitude { get; set; }
    public double Latitude { get; set; }
}

2) Add it to your EF Entity Model

public class User
{
    public Location Location { get; set; }
}

3) Hide it in your modelbuilder

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>().Ignore(x => x.Location);
}

4) Generate a Migration (Add-Migration migrationname)

5) Go to your migration file 1231randomnumbers1231_migrationname.cs and add the following (this way we create another column of type geography named Location) and then update your database (update-database):

migrationBuilder.Sql(@"ALTER TABLE [dbo].[User] ADD [Location] geography NULL");

6) (optional) I created a static class to update the db, handy if you have a Location column in mulple tables.

public static class GeneralDB
{

    public static async Task UpdateLocation(DbContext ctx, string table, Location location, int id)
    {
        Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");

        string query = String.Format(@"UPDATE [dbo].[{0}] SET Location = geography::STPointFromText('POINT(' + CAST({1} AS VARCHAR(20)) + ' ' + CAST({2} AS VARCHAR(20)) + ')', 4326) WHERE(ID = {3})"
        , table.ToLower(), location.Longitude, location.Latitude, id);
        await ctx.Database.ExecuteSqlCommandAsync(query);
    }
    public static async Task<Location> GetLocation(DbContext ctx, string table, int id)
    {
        Location location = new Location();

        using (var command = ctx.Database.GetDbConnection().CreateCommand())
        {
            string query = String.Format("SELECT Location.Lat AS Latitude, Location.Long AS Longitude FROM [dbo].[{0}] WHERE Id = {1}"
                , table, id);
            command.CommandText = query;
            ctx.Database.OpenConnection();
            using (var result = command.ExecuteReader())
            {
                if (result.HasRows)
                {
                    while (await result.ReadAsync())
                    {
                        location.Latitude = result.GetDouble(0);
                        location.Longitude = result.GetDouble(1);
                    }
                }

            }
        }

        return location;
    }
}

This only works in EF Core 2.0

Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-US");

For EF Core 1.0 you would have to find an alternative way to replace a ',' with '.'. A good old fashion .Replace() method could do the job.

location.Longitude.ToString().Replace(',', '.')

7) CRUD Examples:

7.1: Read

public async Task<User> GetByIdAsync(int id)
{
    User user =  await ctx.User.AsNoTracking().SingleOrDefaultAsync(x => x.Id == id);

    user.Location = await GeneralDB.GetLocation(ctx, "user", id);
    return user;
}

7.2: Create

public async Task<User> CreateAsync(User entity)
{

    ctx.User.Add(entity);
    await ctx.SaveChangesAsync();
    await GeneralDB.UpdateLocation(ctx, "user", entity.Location, entity.Id);
    return entity;  
}

7.3: Update

public async Task<User> UpdateAsync(User entity)
{
    ctx.User.Attach(entity);
    ctx.Entry<User>(entity).State = EntityState.Modified;
    await ctx.SaveChangesAsync();

    await GeneralDB.UpdateLocation(ctx, "user", entity.Location, entity.Id);

    return entity;
}

这篇关于实体框架核心:此平台不支持类型Udt。 (空间数据 - 地理)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆