如何解决entity framework 5中snakecase id列的错误"errorMissingColumn"?
How to solve the error "errorMissingColumn" on a snakecase id column in entity framework 5?
我正在构建一个 API,它使用 DotNet 5.0、JsonAPIDotNetCore 和 EntityFramework 访问 PostgreSQL 数据库。我已经用 dotnet-ef 生成了我的模型和我的 DbContext,因为我正在做 database-first(不久的将来数据库会发生变化)。当我启动 API 并尝试访问资源时,API 在调试控制台中响应错误 500 并显示此错误:
Exception data:
Severity: ERROR
SqlState: 42703
MessageText: column j.id doesn't exist
Position: 56
File: d:\pginstaller_13.auto\postgres.windows-x64\src\backend\parser\parse_relation.c
Line: 3514
Routine: errorMissingColumn
数据库
Table Jobs
我正在尝试访问:
列
类型
排序规则
可空
默认
id_job
bigint
不为空
始终作为身份生成
inserted_date
带时区的时间戳
不为空
路径
ltree
不为空
姓名
字符变化(260)
不为空
索引:
"Jobs_pkey" PRIMARY KEY, btree (id_job)
引用者:
TABLE ""Versions"" CONSTRAINT "Versions_id_job_fkey" FOREIGN KEY (id_job) REFERENCES "Jobs"(id_job) NOT VALID
注意,我使用 snake_case 证明是 postgresql naming convention
型号
然后我使用 the command documented by the Npgsql EF Core provider 生成我的 DbContext
。这是带有注释的模型:
[DisplayName("job")]
[Table("Jobs")]
public partial class Job : Identifiable
{
public Job()
{
Versions = new HashSet<Version>();
}
[Attr(PublicName = "id-job")]
public long IdJob { get; set; }
[Attr(PublicName = "inserted-date")]
public DateTime InsertedDate { get; set; }
[Attr(PublicName = "path")]
public string Path { get; set; }
[Attr(PublicName = "name")]
public string Name { get; set; }
[Attr(PublicName = "versions")]
[ForeignKey("id_version")]
public virtual ICollection<Version> Versions { get; set; }
}
DbContext
这里是模型构建器的摘录(使用 Fluent API):
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasPostgresExtension("adminpack")
.HasPostgresExtension("ltree")
.HasAnnotation("Relational:Collation", "French_France.1252");
modelBuilder.Entity<Job>(entity =>
{
entity.HasKey(e => e.IdJob)
.HasName("Jobs_pkey");
entity.Property(e => e.IdJob)
.HasColumnName("id_job")
.UseIdentityAlwaysColumn();
entity.Property(e => e.InsertedDate)
.HasColumnType("timestamp with time zone")
.HasColumnName("inserted_date");
entity.Property(e => e.Name)
.IsRequired()
.HasMaxLength(260)
.HasColumnName("name");
entity.Property(e => e.Path)
.IsRequired()
.HasColumnType("ltree")
.HasColumnName("path");
});
[...]
OnModelCreatingPartial(modelBuilder);
}
服务配置
最后,在服务配置中,我添加了带有连接字符串和命名约定的 DbContext as proposed by the Npgsql EF Core provider documentation:
services.AddDbContext<MyDatabaseDbContext>(options =>
options.UseNpgsql(Configuration.GetConnectionString("MyConnectionString"))
.UseSnakeCaseNamingConvention());
CsProj
这是 csproj 文件:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="EFCore.NamingConventions" Version="5.0.2" />
<PackageReference Include="EntityFramework" Version="6.4.4" />
<PackageReference Include="JsonApiDotNetCore" Version="4.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.8">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.8">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.3" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.7" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
</ItemGroup>
</Project>
经过一些实验,Entity Framework 似乎将 snake_case 列名称 "id_something"
或 "something_id"
解析为 "id"
。这是 Entity Framework 的正常行为吗?如何在不影响数据库命名约定的情况下更改它?
据Steve Py (Thank you very much), the problem come from JsonApiDotNetCore on the id serializing推测。
型号
在我的 Job
模型中,我需要更改资源 ID 的名称(此处为 JobId
),因为 Id
是 属性 的 Identifiable
覆盖。您需要将 Id 属性 的类型指定为通用接口 Identifiable<TId>
。所以我改变了模型的那些部分:
public partial class Job : Identifiable
{
[...]
[Attr(PublicName = "id-job")]
public long IdJob { get; set; }
[...]
}
为此:
public partial class Job : Identifiable<long>
{
[...]
[Attr(PublicName = "id-job")]
public override long Id { get; set; }
[...]
}
我不得不重命名 DbContext 中出现的所有 IdJob。
控制器
最后,我设置我的控制器,指定 JsonApiController<TResource, TId>
and IResourceService<TResource, TId>
的资源标识符类型如下:
namespace TalendExplorerAPI.Controllers
{
public class JobController : JsonApiController<Job, long>
{
public JobController(IJsonApiOptions options, ILoggerFactory loggerFactory,
IResourceService<Job, long> resourceService)
: base(options, loggerFactory, resourceService)
{
}
}
}
如果您使用的是 VSCode,您的控制器上可能有两个编译器错误。如果是这种情况,只需重新启动 IDE.
我正在构建一个 API,它使用 DotNet 5.0、JsonAPIDotNetCore 和 EntityFramework 访问 PostgreSQL 数据库。我已经用 dotnet-ef 生成了我的模型和我的 DbContext,因为我正在做 database-first(不久的将来数据库会发生变化)。当我启动 API 并尝试访问资源时,API 在调试控制台中响应错误 500 并显示此错误:
Exception data:
Severity: ERROR
SqlState: 42703
MessageText: column j.id doesn't exist
Position: 56
File: d:\pginstaller_13.auto\postgres.windows-x64\src\backend\parser\parse_relation.c
Line: 3514
Routine: errorMissingColumn
数据库
Table Jobs
我正在尝试访问:
列 | 类型 | 排序规则 | 可空 | 默认 |
---|---|---|---|---|
id_job | bigint | 不为空 | 始终作为身份生成 | |
inserted_date | 带时区的时间戳 | 不为空 | ||
路径 | ltree | 不为空 | ||
姓名 | 字符变化(260) | 不为空 |
索引:
"Jobs_pkey" PRIMARY KEY, btree (id_job)
引用者:
TABLE ""Versions"" CONSTRAINT "Versions_id_job_fkey" FOREIGN KEY (id_job) REFERENCES "Jobs"(id_job) NOT VALID
注意,我使用 snake_case 证明是 postgresql naming convention
型号
然后我使用 the command documented by the Npgsql EF Core provider 生成我的 DbContext
。这是带有注释的模型:
[DisplayName("job")]
[Table("Jobs")]
public partial class Job : Identifiable
{
public Job()
{
Versions = new HashSet<Version>();
}
[Attr(PublicName = "id-job")]
public long IdJob { get; set; }
[Attr(PublicName = "inserted-date")]
public DateTime InsertedDate { get; set; }
[Attr(PublicName = "path")]
public string Path { get; set; }
[Attr(PublicName = "name")]
public string Name { get; set; }
[Attr(PublicName = "versions")]
[ForeignKey("id_version")]
public virtual ICollection<Version> Versions { get; set; }
}
DbContext
这里是模型构建器的摘录(使用 Fluent API):
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasPostgresExtension("adminpack")
.HasPostgresExtension("ltree")
.HasAnnotation("Relational:Collation", "French_France.1252");
modelBuilder.Entity<Job>(entity =>
{
entity.HasKey(e => e.IdJob)
.HasName("Jobs_pkey");
entity.Property(e => e.IdJob)
.HasColumnName("id_job")
.UseIdentityAlwaysColumn();
entity.Property(e => e.InsertedDate)
.HasColumnType("timestamp with time zone")
.HasColumnName("inserted_date");
entity.Property(e => e.Name)
.IsRequired()
.HasMaxLength(260)
.HasColumnName("name");
entity.Property(e => e.Path)
.IsRequired()
.HasColumnType("ltree")
.HasColumnName("path");
});
[...]
OnModelCreatingPartial(modelBuilder);
}
服务配置
最后,在服务配置中,我添加了带有连接字符串和命名约定的 DbContext as proposed by the Npgsql EF Core provider documentation:
services.AddDbContext<MyDatabaseDbContext>(options =>
options.UseNpgsql(Configuration.GetConnectionString("MyConnectionString"))
.UseSnakeCaseNamingConvention());
CsProj
这是 csproj 文件:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="EFCore.NamingConventions" Version="5.0.2" />
<PackageReference Include="EntityFramework" Version="6.4.4" />
<PackageReference Include="JsonApiDotNetCore" Version="4.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="5.0.8">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="5.0.8">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.3" />
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="5.0.7" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="5.6.3" />
</ItemGroup>
</Project>
经过一些实验,Entity Framework 似乎将 snake_case 列名称 "id_something"
或 "something_id"
解析为 "id"
。这是 Entity Framework 的正常行为吗?如何在不影响数据库命名约定的情况下更改它?
据Steve Py (Thank you very much), the problem come from JsonApiDotNetCore on the id serializing推测。
型号
在我的 Job
模型中,我需要更改资源 ID 的名称(此处为 JobId
),因为 Id
是 属性 的 Identifiable
覆盖。您需要将 Id 属性 的类型指定为通用接口 Identifiable<TId>
。所以我改变了模型的那些部分:
public partial class Job : Identifiable
{
[...]
[Attr(PublicName = "id-job")]
public long IdJob { get; set; }
[...]
}
为此:
public partial class Job : Identifiable<long>
{
[...]
[Attr(PublicName = "id-job")]
public override long Id { get; set; }
[...]
}
我不得不重命名 DbContext 中出现的所有 IdJob。
控制器
最后,我设置我的控制器,指定 JsonApiController<TResource, TId>
and IResourceService<TResource, TId>
的资源标识符类型如下:
namespace TalendExplorerAPI.Controllers
{
public class JobController : JsonApiController<Job, long>
{
public JobController(IJsonApiOptions options, ILoggerFactory loggerFactory,
IResourceService<Job, long> resourceService)
: base(options, loggerFactory, resourceService)
{
}
}
}
如果您使用的是 VSCode,您的控制器上可能有两个编译器错误。如果是这种情况,只需重新启动 IDE.