Entity Framework将RoomLocation属性映射为指定蛇形命名字段的问题
Got it, let's tackle this mapping problem you're having. Since you're already using the SnakeCaseNamingConvention with Npgsql, we just need to ensure the nested RoomLocation properties get prefixed with location_ in your database table. Here are two straightforward ways to do this:
1. Using Fluent API (Recommended for Flexibility)
Fluent API gives you full control over the mapping, and works seamlessly with your existing snake case convention. In your DbContext's OnModelCreating method, configure the Room entity to treat RoomLocation as an owned type (a value object that's part of the Room entity, not a separate table):
protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); // Keep your existing snake case convention enabled modelBuilder.HasPostgresSnakeCaseNamingConvention(); // Configure the RoomLocation owned type with custom column names modelBuilder.Entity<Room>() .OwnsOne(room => room.Location, locationBuilder => { locationBuilder.Property(loc => loc.Floor).HasColumnName("location_floor"); locationBuilder.Property(loc => loc.Building).HasColumnName("location_building"); locationBuilder.Property(loc => loc.Room).HasColumnName("location_room"); }); }
Why this works:
- Owned types in EF Core map their properties directly to the parent entity's table (so no separate
RoomLocationtable is created). - We explicitly set each column name to match your desired
location_prefix + snake case property name, which aligns with your existing convention.
2. Using Data Annotations (Simpler for Basic Cases)
If you prefer attribute-based configuration, you can use the [Owned] and [Column] annotations directly on your classes:
First, mark RoomLocation as an owned type (either on the class itself or on the Location property in Room):
public class Room { [Key] public Guid Id { get; set; } public string Title { get; set; } [Owned] // Mark Location as an owned property public RoomLocation Location { get; set; } public DateTime CreationDate { get; set; } public DateTime ModificationDate { get; set; } } // Alternatively, mark the RoomLocation class as owned: // [Owned] // public class RoomLocation { ... }
Then, add [Column] annotations to each property in RoomLocation to specify the exact column name:
public class RoomLocation { [Column("location_floor")] public int Floor { get; set; } [Column("location_building")] public int Building { get; set; } [Column("location_room")] public int Room { get; set; } }
Quick Note on Your Old Project Oddity
Regarding the time you forgot to add builder.HasKey but it still worked with user_-prefixed queries: That's likely because EF Core's default primary key convention kicked in. EF automatically recognizes properties named Id (or <EntityName>Id, like RoomId) as the primary key without explicit configuration. The user_ prefix you saw was probably a side effect of the naming convention applied at the time, but relying on defaults can lead to unexpected behavior later—so sticking with explicit [Key] or fluent configuration is always safer.
内容的提问来源于stack exchange,提问作者Jamal Abo Mokh

