How do I map a column to uppercase in .NET 4.5 C#

2019-05-11 12:41发布

问题:

I'm using C#, .NET 4.5 and Entity Framework 6 in my project. It uses both Oracle and SQL Server, depending on the installation at the client.

The approach is database-first, as this database existed already by the time we decided to change the ORM from NHibernate to Entity Framework 6.

The mapping looks like this:

ToTable(schema + ".Motorista");
Property(x => x.Criacao).HasColumnName("criacao").IsOptional();

The table and column names are all in PascalCase in the mapping, which works fine with SQL Server but, in Oracle, all the names are UpperCase which causes an error:

ORA-00942: table or view does not exist

If I manually make it uppercase, then it works fine on Oracle. But I can't do that because of compatibility to SQL Server.

How can I say to Entity Framework to uppercase all the names when using Oracle?

Can I use conventions in this scenario?

回答1:

Check the providerName attribute in the named connection string to see if your connection is for SQL Server or Oracle (OR add a redundant value in the appSettings section of the configuration). Then do what @AaronLS suggested and add a helper method to case your names correctly and apply any additional formatting. The helper method should be tasked with checking the database type as mentioned above and applying or not applying casing/formatting.

Here is an example.

public class MyDbContext : DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new SomeMappedTypeMapper());
        base.OnModelCreating(modelBuilder);
    }
}

public class SomeMappedType
{
    public int SomeMappedColumnId { get; set; }
    public string SomeMappedColumn { get; set; }
}

public class SomeMappedTypeMapper : EntityTypeConfiguration<SomeMappedType>
{
    public SomeMappedTypeMapper()
    {
        this.HasKey(x => x.SomeMappedColumnId);
        this.ToTable("SomeMappedType"); // If needed, apply the same technique as used in the column name extension

        this.Property(x => x.SomeMappedColumnId).HasColumnNameV2("SomeMappedColumnId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
        this.Property(x => x.SomeMappedColumn).HasColumnNameV2("SomeMappedColumn");
    }
}

public static class TypeHelper
{
    private static bool isOracle;
    static TypeHelper()
    {
        isOracle = System.Configuration.ConfigurationManager.ConnectionStrings["yourDbConnectionName"].ProviderName.IndexOf("oracle", StringComparison.OrdinalIgnoreCase) >= 0;
    }
    public static PrimitivePropertyConfiguration HasColumnNameV2(this PrimitivePropertyConfiguration property, string columnName)
    {
        if (isOracle)
            return property.HasColumnName(columnName.ToUpper());
        return property.HasColumnName(columnName);
    }
}


回答2:

When the database names (tables and columns) are equal to the class and property names in the class model it's very easy to introduce custom code-first conventions:

In the context's OnModelCreating overload you can add these lines to add conventions how table and column names will be derived from the class and property names, respectively:

modelBuilder.Types().Configure
    (c => c.ToTable(c.ClrType.Name.ToUpper(), schema));

modelBuilder.Properties().Configure
    (c => c.HasColumnName(c.ClrPropertyInfo.Name.ToUpper()));

Of course you should do this conditionally, i.e. when connecting to Oracle. For instance by checking a global constant like OnOracle that you could set by

ConfigurationManager.ConnectionStrings[0].ProviderName
    == "System.Data.OracleClient"

on application start up.



回答3:

Consider a table called "Person" with a column called "Name" in SQL Server but in oracle the table is called "PERSON" with a column called "NAME".

We were able to use our models generated against sql server on our oracle database by adding the following code to the DBContext classe's OnModelCreating

modelBuilder.Entity<Person>()
  .HasEntitySetName("Person")
  .ToTable("PERSON");

modelBuilder.Entity<Person>()
  .Property(t => t.Name)
  .HasColumnName("NAME");