I recently upgraded a project to EF Core 8 in order to take advantage of recently added JSON type capabilities. The project is an ASP.NET Core 8 Web API written in C#. The database is PostgreSQL 16.
EF Core thinks that I am defining a property twice and I think I know why, but I don't know how to get around it.
I use Pascal casing in my model names and property names.
public class Article
{
public string? Id { get; set; }
public string? DocId { get; set; }
public string? ArticleBody { get; set; }
public List<PointGeometry>? PointArray { get; set; }
public PointGeometry? Geometry { get; set; }
}
Below I'm defining the JSON properties according to these docs. But I also want to use snake_casing in the actual database table names and column names. So I'm defining the column names in the DbContext class:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<Article>(a =>
{
a.ToTable("article");
a.Property("Id").HasColumnName("id");
a.Property("DocId").HasColumnName("doc_id");
a.Property("ArticleBody").HasColumnName("article_body");
a.Property("PointArray").HasColumnName("point_array");
a.Property("Geometry").HasColumnName("geometry");
a.OwnsMany<PointGeometry>(x => x.PointArray, y => y.ToJson());
a.OwnsOne<PointGeometry>(x => x.Geometry, y => y.ToJson());
});
}
This is working fine for all columns and properties except for those last two that hold JSON data. The point_array and geometry columns are of jsonb type.
Method from my repository class to run a query:
public async Task<List<Article>> GetAsync(string where, List<string>? outFields = null, int? offset = null, int? limit = null)
{
string offsetLimit = limit != null && offset != null ? $" offset {offset} limit {limit}" : "";
FormattableString query = $"select * from article where {where} {offsetLimit}";
var articles = _context.Article.FromSql(query).ToList();
return articles;
}
When EF Core queries it throws this exception:
The property or navigation 'Geometry' cannot be added to the 'Article' type because a property or navigation with the same name already exists on the 'Article' type.
I suspect EF Core is trying to define Geometry a second time when I call the OwnsOne() method when it has already defined it once when I call the HasColumnName() method two lines prior.
Is there another way to explicitly define the column name in camel case on a property that is mapped to a JSON type?
UPDATE: As suggested by @GertArnold I renamed the properties in my model class as follows:
"Geometry" -> "geometry"
"PointArray" -> "point_array"
And it runs queries without errors now. This work-around does the job but I'd rather not break convention with these property names just to avoid confusing EF Core. I'm still looking for a solution that doesn't break the naming convention for jsonb properties that need explicit column renaming and defining as a JSON type.