C#中ValueObject报错:实体类型SkillLevel需定义主键
EF Core值对象主键错误解决
我的代码
SkillLevel值对象类
using System.Runtime.CompilerServices; using System.Collections.Generic; namespace sales.Domain.Common.ValueObjects { public record SkillLevel { List<Skill> Skill; List<Level> Level; private SkillLevel() { } public SkillLevel(List<Skill> skill, List<Level> level) { Skill = skill; Level = level; } } }
EmployeeSkillType配置类
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Metadata.Builders; using Pluralize.NET; using sales.Domain.Common.BaseEntities; using sales.Domain.Entities.Payroll; namespace sales.Infrastructure.Data.Configs.Payroll { internal class EmployeeSkillTypeConfiguration : IEntityTypeConfiguration<EmployeeSkillType> { public void Configure(EntityTypeBuilder<EmployeeSkillType> builder) { builder.ToTable(new Pluralizer().Pluralize(nameof(EmployeeSkillType))); builder.HasKey(ii => new { ii.EmployeeGuid, ii.SkillTypeGuid }); builder.HasOne(e => e.Employee) .WithMany(es => es.EmployeeSkillType); builder.HasOne(st => st.SkillType) .WithMany(es => es.EmployeeSkillType); builder.HasMany(sl => sl.SKillLevels).WithOne(); builder.Navigation(e => e.Employee).AutoInclude(); builder.Navigation(st => st.SkillType).AutoInclude(); } } }
遇到的错误
实体类型'SkillLevel'需要定义主键。如果您打算使用无键实体类型,请在'OnModelCreating'中调用'HasNoKey'。有关无键实体类型的更多信息...
已尝试操作
- 尝试将
SkillLevels改为jsonb类型存储,但出现其他错误。
解决方案
SkillLevel是值对象,不是独立实体,EF Core默认会把它当成实体处理,要明确告诉EF Core它的角色,以下两种方案任选:
方案1:配置为拥有类型(Owned Type)
把原来的HasMany配置替换成拥有类型的配置,EF会把值对象作为从属数据存储,无需主键:
// 替换builder.HasMany(sl => sl.SKillLevels).WithOne();这一行 builder.OwnsMany(sl => sl.SKillLevels, ownedBuilder => { // 如果Skill和Level也是值对象,继续配置它们的拥有关系 ownedBuilder.OwnsMany(s => s.Skill); ownedBuilder.OwnsMany(l => l.Level); // 若需要自定义列名或约束,可在此添加配置 });
方案2:正确配置JSONB列存储
之前转jsonb出错大概率是没正确配置序列化/反序列化,按下面步骤来:
- 确保数据库支持JSONB(比如PostgreSQL)
- 修改配置类中的属性映射:
// 替换原来的HasMany配置 builder.Property(e => e.SKillLevels) .HasColumnType("jsonb") .HasConversion( levels => System.Text.Json.JsonSerializer.Serialize(levels, null), json => System.Text.Json.JsonSerializer.Deserialize<List<SkillLevel>>(json, null) );
同时注意:
SkillLevel、Skill、Level需要有无参构造函数(或者在JsonSerializer中配置允许使用私有构造函数)- 把类中的私有属性改为public,或者配置JsonSerializer能访问私有成员
- 检查
SKillLevels的拼写(S大写、kill小写,可能是笔误)
内容的提问来源于stack exchange,提问作者alyawdi
相关产品推荐
相关产品推荐

