Configure Entity Framework v6 Code-First Identifiers to use ALL CAPS - c#

I would like Entity Framework v6 to not use quotes around identifiers when executing transactions against the database. Is it possible to configure the DbContext to do this without creating a configuration file for every entity?
For example:
Instead of
SELECT "ApplicationId"
FROM "dbo"."Applications";
I want
SELECT ApplicationId
FROM dbo.Applications;
Will Entity Framework be able to correctly map properties and entities to the database fields and tables correctly?
EDIT:
Rather than try to eliminate the quotation marks, I should have indicated that my goal is to interface with an Oracle DB. Oracle will require using quotation marks around identifiers that contain lowercase letters. So, I should probably change my request to indicate that I need all uppercase identifiers.
I came up with part of a solution in the OnModelCreating method of the DbContext, but it won't handle Foreign Key identifiers:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Properties()
.Configure(c => c.HasColumnName(c.ClrPropertyInfo.Name.ToUpperInvariant()));
modelBuilder.Types()
.Configure(c => c.ToTable(c.ClrType.Name.ToUpperInvariant()));
}

You can put the foreign key properties in your class, and then map their database column. Like this How to configure DbContext to work with Oracle ODP.Net and EF CodeFirst?
Or, if you don't want to put the foreign key property in the classes, you should use the fluent API to map the foreign key using uppercase letters. Like this example:
modelBuilder.Entity<Course>()
.HasRequired(c => c.Department)
.WithMany(t => t.Courses)
.Map(m => m.MapKey("CHANGEDDEPARTMENTID"));

Related

Avoid using discriminator in EF Core when dealing with inheritance

Problems started after switching from EF to EF Core (3.1).
I have a base abstract class and a derived class which is created dynamicaly in runtime (using reflection).
entity configuration of my base type was (EF):
ToTable("TableName", "dbo");
HasKey(t => t.Id);
HasRequired(t => t.prop1).WithMany().HasForeignKey(t => t.prop1);
Property(t => t.prop2).IsRequired();
Property(t => t.prop3).IsRequired();
I built base class with this configuration and dynamic class with modelBuilder.Entity(type).
And everything worked fine. I could get instances of my base class using context.Objects and instances of the dynamic class using Activator.CreateInstance(type).
Now I have same configuration but for EF Core:
builder.ToTable("TableName", "dbo");
builder.HasKey(t => t.Id);
builder.HasOne(t => t.prop1).WithMany().HasForeignKey(t => t.prop1);
builder.Property(t => t.prop2).IsRequired();
builder.Property(t => t.prop3).IsRequired();
But in EF Core getting objects from context gives an error "Invalid column name 'Discriminator'". Yes, I don't have discriminator column in my table (apparently it's required when TPH pattern is used) but it worked perfectly without it in EF. How did EF dealt with inheritance in that case? Moreover, creating such column and populating it with the same data (derived class name) seems to be useless. It feels like there should be something I'm missing.
So, my question is:
Is there any way to fix the problem without creating a discriminator column?
A default EF TPH will generally go across to EF Core without too many issues, however the customisation options are different between the two, for instance in core we can now easily manipulate the discriminator via fluent notation: https://www.learnentityframeworkcore.com/configuration/fluent-api/hasdiscriminator-method
Check that your base class is NOT abstract: https://stackoverflow.com/a/34646164/1690217
If your base class IS abstract then you will have to manually configure the Discriminator column: https://www.learnentityframeworkcore.com/inheritance/table-per-hierarchy#configuration
Also check that your database schema from the previous EF migrations actually has the Discriminator column and that it is a string type, the actual values should be the name of the types, however it is possible that you have configured or applied conventions elsewhere that override the default behaviour (in either the EF or the EF Core implementations)
If you include the actual schema in the database or the migration entries that build the tables you might get a more definitive answer.

Entity Framework 6 trying to drop non existent Index when renaming

As a newcomer to EF migrations, I was surprised by the following behaviour, and wondered if it's intentional (i.e. there's a switch to make it go away).
When I rename a column, I have the following relevant lines inside an EntityTypeConfiguration class:
Property(x => x.MyColumn).HasColumnName(#"MyColumn").HasColumnType("nvarchar").IsOptional();
And, crucially:
HasOptional(a => a.RelatedTable).WithMany(b => b.ThisTable).HasForeignKey(c => c.MyColumn).WillCascadeOnDelete(false);
Which is, as I understand it, establishing a foreign key relationship. When I rename MyColumn to MyColumn2, the migration that is created looks like this:
public override void Up()
{
RenameColumn(table: "dbo.ThisTable", name: "MyColumn", newName: "MyColumn2");
RenameIndex(table: "dbo.ThisTable", name: "IX_MyColumn", newName: "IX_MyColumn2");
}
However, MyColumn is not indexed on ThisTable. I realise that creating indexes for a foreign key relationship is advisable; is this why EF assumes there is one?
Note that the EF model was generated from the DB initially using the EF Reverse POCO Generator.
It's intentional. Code First migrations are based purely on model (data annotations, fluent configuration) and assume the previous database state is created using migration as well. Since EF default convention is to create index for FK columns, the migration assumes that the index exists and tries to rename it.
You can solve it in two ways. Either edit the generated migration and remove the RenameIndex (and other index related commands), or turn off (remove) the default FK index convention:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<ForeignKeyIndexConvention>();
// ...
}
Please note that the later will affect your future model modifications and you have to explicitly opt for index on FK columns (which cannot be done if the entity does not have explicit FK property). Also if you rename some of the exiting FK columns which do have an index, you'll have to add RenameIndex (or DropIndex/CreateIndex`) commands manually.

Split ASP .Net Identity Entity across multiple tables

Is there a simple way to split ASP .Net Identity entities across multiple tables? I know you can change the name of the tables used by Identity using OnModelCreating.
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<IdentityUser>().ToTable("IdentityUser").Property(p => p.Id).HasColumnName("UserId");
}
Can you similarly use an override in OnModelCreating or elsewhere to split across multiple tables? I tried using a map:
modelBuilder.Entity<IdentityUser>().Map(m =>
{
m.Properties(t => new {t.Id, t.UserName});
m.ToTable("User");
});
but I receive an error indicating UserName is already mapped. The non-key property 'UserName' is mapped more than once. Ensure the Properties method specifies each non-key property only once.
I assume this is due to the default mapping of Identity already having UserName mapped. Can I override this or remove the default mapping somehow in order to achieve splitting the IdentityUser entity across multiple tables?

EF4 CTP5 - Many To One Column Renaming

How do I override the default convention for the foreign key column in EF4 to specify a different column name?
For example, I have one entity with a property called Parent that references to other one of the same type.
EF4 tries to resolve the relation by looking for the foreign key named EntityId, but in my DB schema it is Entity_Id. How do I tell EF that the FK column name is not EntityId?
I've tried the following:
modelBuilder.Entity<SomeEntity>()
.HasOptional(m => m.Parent)
.WithMany()
.IsIndependent()
.Map(m => m.MapKey(k => k.Id, "Entity_Id")));
But I get an exception saying: Sequence contains more than one matching element.
Any help on this?
Thanks!
First: Upgrade to EF 4.1 RTW. CTP 5 is outdated and contains potentially many bugs which are fixed now.
If you have done the upgrade the following should work:
modelBuilder.Entity<SomeEntity>()
.HasOptional(m => m.Parent)
.WithMany()
.Map(c => c.MapKey("Entity_Id"));

EF 4 Code First: How can I modify naming conventions for generated junction tables?

I'm integrating with an existing database, so I would like the tables generated by my EF4 Code First code to adhere to the table naming conventions which are already in place.
The existing convention is the singular entity name, prefixed with a lowercase "t" (e.g tProduct), and joined with an underscore for junction tables (e.g tProduct_tOffer).
I've achieved this with all the 'standard' tables using the code below. In my DbContext I have:
protected override void OnModelCreating(ModelBuilder modelBuilder) {
modelBuilder.Conventions.Remove<PluralizingEntitySetNameConvention>();
modelBuilder.Conventions.Add<TableNamePrefixConvention>();
base.OnModelCreating(modelBuilder);
}
And the following class adds the "t" to table names:
public class TableNamePrefixConvention : IConfigurationConvention<Type, EntityTypeConfiguration> {
public void Apply(Type typeInfo, Func<EntityTypeConfiguration> configuration) {
configuration().ToTable("t" + typeInfo.Name);
}
}
However, when a junction table is generated, it doesn't adhere to these conventions. So I now have this kind of thing in the list of tables:
tOffer
tProduct
ProductOffers
In this case, ProductOffers should be named tProduct_tOffer. How can I force the generated junction table to conform to my naming style?
Update: as Ladislav correctly guessed below, I am using CTP5.
As I pointed in the comment custom conventions are not available in RC version and will not be available in RTW as well (official announcement).
You must map it manually:
modelBuilder.Entity<Offer>()
.HasMany(o => o.Products)
.WithMany(p => p.Offers)
.Map(m => m.ToTable("tProduct_Offer"));
The code snippet is RC version. CTP5 used one more step with IsIndependent() but it was removed in RC.

Categories

Resources