efcore/EFCore.NamingConventions

Please support Json nested name convertions.

ye4241 opened this issue · 3 comments

I noticed that there is a TODO in code:

// TODO: Note that we do not rewrite names of JSON properties (which aren't relational columns).
// TODO: We could introduce an option for doing so, though that's probably not usually what people want when doing JSON

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

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.

@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..]}";
    }
}
  1. 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;
   }
}
  1. 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();
   }
}

@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.