I have a project using the last version of EF CF with PostgreSQL and Npgsql.
My model looks like:
[Table("mytable")]
public class MyTable
{
[Column("id")]
public int Id { get; set; }
[Column("mycolumn")]
public string MyColumn { get; set; }
}
And the database/tables/columns has lowercase names like:
CREATE TABLE mytable
{
id serial,
mycolumn character(50)
}
The Npgsql generates SQL commands with quotation marks so I must use the Data Annotations due the PostgreSQL characteristics, witch is annoying. However I would like to not use quotations delimited names in the database.
Is there a way to configure Npgsql to not include quotation marks when generate commands or force lowercase table/columns names in the generated SQL?
Furthermore, Entity Framework's design makes it particularly friendly for PostgreSQL developers. Entity Framework (EFCore) Core is a lighter weight and more flexible version that specifically enables . NET objects. It reduces the amount of data access code developers need to write, and offers higher-performance APIs.
To demonstrate the usage of Dapper, Entity Framework Core, and both combined, we will implement them each in the 3 Endpoints. For the GetAll Endpoints, we will use Dapper. The GetById Endpoint would use Entity Framework Core with Eager Loading to display the Department Details as well.
If I'm not missing something - you'd want some generic way of changing the naming convention for tables
?
The EF6 has the custom conventions
feature - it's still not official version, but if it works for you, some links...
http://entityframework.codeplex.com/wikipage?title=Custom%20Conventions
In your case, you'd have to implement it for the class/Type
I guess - e.g. (some pseudo code)...
1) implement IConfigurationConvention<Type, EntityTypeConfiguration>
(you can check the EF source for EntityConventionBase
)
2) In the Apply
- change how the Table names are generated via configuration (ToTable()
) - to something like .ToLowerCase()
3) add to conventions...
For example...
public class SmallCapsEntitiesConfigurationConvention
: IConfigurationConvention<Type, EntityTypeConfiguration>
{
public void Apply(Type memberInfo, Func<EntityTypeConfiguration> configuration)
{
configuration().ToTable(memberInfo.Name.ToLowerInvariant(), null);
}
}
You can see one example here
http://blog.cincura.net/233167-custom-conventions-in-entity-framework-6-helping-firebird/
Otherwise, I have no idea about Npgsql
/ PostgreSQL - it did seem a bit 'raw' to me. But you can handle it on the EF side.
Here is an example for EF Core.
Current code convert tables
, properties
, keys
and indexes
to snake case for Postgre
, you can use it as a base for your custom conventions:
using System;
using System.Text.RegularExpressions;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Npgsql;
namespace Database.Customization
{
public class PostgreDbContext : DbContext
{
private static readonly Regex _keysRegex = new Regex("^(PK|FK|IX)_", RegexOptions.Compiled);
public PostgreDbContext(DbContextOptions options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
FixSnakeCaseNames(modelBuilder);
}
private void FixSnakeCaseNames(ModelBuilder modelBuilder)
{
var mapper = new NpgsqlSnakeCaseNameTranslator();
foreach (var table in modelBuilder.Model.GetEntityTypes())
{
ConvertToSnake(mapper, table);
foreach (var property in table.GetProperties())
{
ConvertToSnake(mapper, property);
}
foreach (var primaryKey in table.GetKeys())
{
ConvertToSnake(mapper, primaryKey);
}
foreach (var foreignKey in table.GetForeignKeys())
{
ConvertToSnake(mapper, foreignKey);
}
foreach (var indexKey in table.GetIndexes())
{
ConvertToSnake(mapper, indexKey);
}
}
}
private void ConvertToSnake(INpgsqlNameTranslator mapper, object entity)
{
switch (entity)
{
case IMutableEntityType table:
var relationalTable = table.Relational();
relationalTable.TableName = ConvertGeneralToSnake(mapper, relationalTable.TableName);
if (relationalTable.TableName.StartsWith("asp_net_"))
{
relationalTable.TableName = relationalTable.TableName.Replace("asp_net_", string.Empty);
relationalTable.Schema = "identity";
}
break;
case IMutableProperty property:
property.Relational().ColumnName = ConvertGeneralToSnake(mapper, property.Relational().ColumnName);
break;
case IMutableKey primaryKey:
primaryKey.Relational().Name = ConvertKeyToSnake(mapper, primaryKey.Relational().Name);
break;
case IMutableForeignKey foreignKey:
foreignKey.Relational().Name = ConvertKeyToSnake(mapper, foreignKey.Relational().Name);
break;
case IMutableIndex indexKey:
indexKey.Relational().Name = ConvertKeyToSnake(mapper, indexKey.Relational().Name);
break;
default:
throw new NotImplementedException("Unexpected type was provided to snake case converter");
}
}
private string ConvertKeyToSnake(INpgsqlNameTranslator mapper, string keyName) =>
ConvertGeneralToSnake(mapper, _keysRegex.Replace(keyName, match => match.Value.ToLower()));
private string ConvertGeneralToSnake(INpgsqlNameTranslator mapper, string entityName) =>
mapper.TranslateMemberName(ModifyNameBeforeConvertion(mapper, entityName));
protected virtual string ModifyNameBeforeConvertion(INpgsqlNameTranslator mapper, string entityName) => entityName;
}
}
Update:
If you are working with EF core 3 then Relational()
will cause error as the method was removed lately. Change the definition of the ConvertToSnake
function as following:
private void ConvertToSnake(INpgsqlNameTranslator mapper, object entity)
{
switch (entity)
{
case IMutableEntityType table:
table.SetTableName(ConvertGeneralToSnake(mapper, table.GetTableName()));
if (table.GetTableName().StartsWith("asp_net_"))
{
table.SetTableName(table.GetTableName().Replace("asp_net_", string.Empty));
table.SetSchema("identity");
}
break;
case IMutableProperty property:
property.SetColumnName(ConvertGeneralToSnake(mapper, property.GetColumnName()));
break;
case IMutableKey primaryKey:
primaryKey.SetName(ConvertKeyToSnake(mapper, primaryKey.GetName()));
break;
case IMutableForeignKey foreignKey:
foreignKey.SetConstraintName(ConvertKeyToSnake(mapper, foreignKey.GetConstraintName()));
break;
case IMutableIndex indexKey:
indexKey.SetName(ConvertKeyToSnake(mapper, indexKey.GetName()));
break;
default:
throw new NotImplementedException("Unexpected type was provided to snake case converter");
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With