Reputation: 1
I'm working on a C# Winforms project (targeting .NET Framework 4.6.1) and I want to reflect this function for each DbSet
:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.Property(e => e.Name)
.HasColumnName("name");
}
I need to automate the configuration of my OnModelCreating
method. This is necessary because, due to legacy reasons, I must create all database columns in lowercase in PostgreSQL. I haven't found a setting in PostgreSQL that allows me to query tables like SELECT * FROM User
without using quotes unless the tables and columns are created in lowercase. Also using data annotations is not an option since I need this in Pascal case for another reason.
I have successfully converted table names to lowercase, but I'm struggling with dynamically configuring the property names (i.e., column names) using reflection.
Here's the approach I'm currently using:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Dynamically iterate through all DbSet properties
var dbSetProperties = this.GetType().GetProperties()
.Where(p => p.PropertyType.IsGenericType &&
p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>));
foreach (var property in dbSetProperties)
{
var entityType = property.PropertyType.GenericTypeArguments[0]; // Entity type
var tableName = entityType.Name.ToLower(); // Convert table name to lowercase
// Register the entity and set the table name
var method = modelBuilder.GetType()
.GetMethod("Entity", new Type[] { })
.MakeGenericMethod(entityType); // Create generic method
var entityConfiguration = method.Invoke(modelBuilder, null); // Call the Entity method
// Set the table name
var toTableMethod = entityConfiguration.GetType()
.GetMethod("ToTable", new[] { typeof(string) });
toTableMethod.Invoke(entityConfiguration, new object[] { tableName });
}
}
However, I need to also set the property names (column names) to lowercase, but I'm not sure how to do that dynamically.
So far I reached this point, but I always fail on loading the property Method and use the lambda expression on it.
void LowerProperties(DbModelBuilder modelBuilder)
{
var dbSetProperties = this.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.PropertyType.IsGenericType &&
p.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>));
foreach (var dbSetProperty in dbSetProperties)
{
Type entityType = dbSetProperty.PropertyType.GetGenericArguments()[0];
var properties = entityType.GetProperties();
foreach (var property in properties)
{
string propertyName = property.Name;
MethodInfo entityMethod = modelBuilder.GetType()
.GetMethod("Entity")
.MakeGenericMethod(entityType);
object entityConfig = entityMethod.Invoke(modelBuilder, null);
ParameterExpression param = Expression.Parameter(entityType, "e");
MemberExpression propertyAccess = Expression.Property(param, propertyName);
LambdaExpression lambda = Expression.Lambda(propertyAccess, param);
Type configType = typeof(StructuralTypeConfiguration<>).MakeGenericType(entityType);
dynamic typ;
if (property.PropertyType == typeof(int))
{
typ = typeof(Func<,>).MakeGenericType(entityType, typeof(decimal));
}
else
{
typ = typeof(Func<,>).MakeGenericType(entityType, property.PropertyType);
}
MethodInfo propertyMethod = configType.GetMethod("Property",
BindingFlags.Public | BindingFlags.Instance,
null,
new Type[] { typ },
null);
object stringPropertyConfig = propertyMethod.Invoke(entityConfig, new object[] { lambda });
MethodInfo hasColumnNameMethod = stringPropertyConfig.GetType()
.GetMethod("HasColumnName", new[] { typeof(string) });
hasColumnNameMethod.Invoke(stringPropertyConfig, new object[] { propertyName.ToLower() });
}
}
}
Can anyone help me figure out how to achieve this?
Upvotes: 0
Views: 54
Reputation: 88852
It took me a while to remember how to do this in EF6. You should really migrate to EF Core and .NET Core. It has Windows Forms. Anyway, like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Properties().Configure( p => p.HasColumnName(p.ClrPropertyInfo.Name.ToLower()) );
base.OnModelCreating(modelBuilder);
}
Upvotes: 0