efcore / EFCore.NamingConventions

Entity Framework Core plugin to apply naming conventions to table and column names (e.g. snake_case)
Apache License 2.0
715 stars 73 forks source link

Please support Json nested name convertions. #269

Open ye4241 opened 7 months ago

ye4241 commented 7 months ago

I noticed that there is a TODO in code:

https://github.com/efcore/EFCore.NamingConventions/blob/83a34122a6eb5a314453695a8306a6a8b1226af4/EFCore.NamingConventions/Internal/NameRewritingConvention.cs#L184-L185

Could you please add feature for this?

                    foreach (var property in entityType.GetProperties())
                    {
                        property.Builder.HasNoAnnotation(RelationalAnnotationNames.ColumnName);
                        property.Builder.HasJsonPropertyName(_namingNameRewriter.RewriteName(property.GetColumnName()));
                    }
roji commented 7 months ago

As the comment says, I doubt this is something that a lot of people actually want - the naming conventions inside JSON documents is usually unrelated to the naming conventions of database columns. I'll put this in the backlog for now to gather more feedback/votes.

Rlamotte commented 5 months ago

@ye4241 for your information, I encountered exactly the same problem and searched few hours how to solve it. It's quite sad the plugin EFCore.NamingConventions doesn't take it (at least with a parameter) but you can find my solution below :

  1. Create a stringExtension to be able to convert to your defined convention (in my case, camelCase) :

    public static class StringExtension
    {
    public static string ToCamelCase(this string? text)
    {
        if (string.IsNullOrEmpty(text))
        {
            return string.Empty;
        }
    
        //If text is in snake_case, convert each word inside to camelCase
        if (text.Contains('_'))
        {
            var newText = "";
            foreach (var word in text.Split('_'))
            {
                newText += $"{word.ToCamelCase()}_";
            }
            return newText[..^1];
        }
    
        return $"{text.First().ToString().ToLowerInvariant()}{text[1..]}";
    }
    }
  2. Add a specific modelBuilder extension to apply this convention to json owned properties :

    public static class ModelBuilderExtension
    {
    public static ModelBuilder ConfigureJsonOwnedPropertiesInCamelCase(this ModelBuilder modelBuilder)
    {
        foreach (var entityType in modelBuilder.Model.GetEntityTypes()
            .Where(entityType => entityType.IsOwned()))
        {
            foreach (var property in entityType.GetProperties())
            {
                if (!property.IsPrimaryKey())
                {
                    property.SetJsonPropertyName(property.GetColumnName().ToCamelCase());
                }
            }
        }
    
        return modelBuilder;
    }
    }
  3. Call this function in your dbContext file :

    public class MyDbContext(DbContextOptions<MyDbContext> options) : DbContext(options)
    {
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Order>().OwnsOne(
            order => order.shippingAddress, ownedNavigationBuilder =>
            {
                ownedNavigationBuilder.ToJson();
                ownedNavigationBuilder.OwnsOne(shippingAddress => shippingAddress.Country);
                ownedNavigationBuilder.OwnsOne(shippingAddress => shippingAddress.Company);
            });
    
        modelBuilder.ConfigureJsonOwnedPropertiesInCamelCase();
    }
    }
ye4241 commented 5 months ago

@Rlamotte Indeed, the underlying logic is to use JsonPropertyName to batch set the properties at each nest elements. The current project already has comprehensive CamelCase-related methods, so the ideal way is to complete these batch settings within the existing project. I will try to see if I can support batch setting the JsonPropertyName attribute at the lower level.