Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Npgsql integration with Entity Framework Code First

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?

like image 812
Max Bündchen Avatar asked Apr 04 '13 14:04

Max Bündchen


People also ask

Can Entity Framework work with PostgreSQL?

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.

Can I use Entity Framework and dapper together?

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.


2 Answers

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.

like image 117
NSGaga-mostly-inactive Avatar answered Sep 18 '22 08:09

NSGaga-mostly-inactive


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");
    }
}
like image 26
AuthorProxy Avatar answered Sep 18 '22 08:09

AuthorProxy