我是.NET core 的初学者。我有两个实体,实体技术和实体技能。每个Tech都有一个Skill列表,Skill有Tech的外键。数据库是用EF core构建的。
实体是这样的:
Tech.cs
public class Tech
{
[Key]
public int Id { get; set; }
public string TechName { get; set; }
public virtual ICollection<Skill> Skills { get; set; } = new List<Skill>();
// for soft delete
public bool isDeleted { get; set; }
}
技能.cs
public class Skill
{
[Key]
public int Id { get; set; }
public string SkillName { get; set; }
// Foreign Key
[Required]
public int TechId { get; set; }
[ForeignKey("TechId")]
[JsonIgnore]
public Tech tech { get; set; }
// For soft delete
public bool isDeleted { get; set; }
}
数据库上下文:
为了技能
public void Configure(EntityTypeBuilder<Skill> builder)
{
builder.ToTable("Skill");
builder.HasKey(x => x.Id);
builder.Property(t => t.Id).IsRequired().ValueGeneratedOnAdd();
builder.Property(x => x.SkillName).HasColumnType("nvarchar(50)");
builder.HasQueryFilter(b => !b.isDeleted);
builder
.HasOne(e => e.tech)
.WithMany(e => e.Skills).HasForeignKey(e => e.TechId).OnDelete(DeleteBehavior.Cascade); ;
ICollection<Skill> skill_1 = new List<Skill>();
skill_1 = AddDotNetSkill();
builder.HasData(skill_1);
}
对于科技
public void Configure(EntityTypeBuilder<Tech> builder)
{
builder.ToTable("Tech");
builder.HasKey(t => t.Id);
builder.Property(t => t.Id).IsRequired().ValueGeneratedOnAdd();
builder.Property(x => x.TechName).HasColumnType("nvarchar(50)");
builder.HasQueryFilter(b => !b.isDeleted);
Tech tech_1 = AddTechDotNet();
Tech tech_2 = AddTechDatabases();
builder.HasData(tech_1);
builder.HasData(tech_2);
}
因此我尝试使用这两个实体创建一个 CRUD API。 get 方法很好,但是当我尝试执行 HttpPost 时,Swagger 会立即回复 400 错误,而无需进入我的控制器。
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-0c523d52d0f3f06ce2a64fe8fe59520a-974d7fc666a3a246-00",
"errors": {
"Skills[0].tech": [
"The tech field is required."
]
}
}
以下是我的控制器:
// POST: api/Techs
[HttpPost]
public ActionResult<Tech> PostTech([FromBody] Tech tech)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_context.Techs.Add(tech);
_context.SaveChanges();
foreach (var skill in tech.Skills)
{
skill.TechId = tech.Id;
_context.Add(skill);
_context.SaveChanges();
}
return Ok(tech);
}
我认为问题出在我的 Tech tech 外键上,如果我能收到任何与此相关的建议,我将非常感激。
通过这样配置模型,EF Core 在它们之间创建“一对多”关系。不需要在FluentApi中明确指出关系(仅针对一对一的需要)
public class Tech
{
//Best way to initialize the collection directly in the model
public Tech()
{
this.Skills = new HashSet<Skill>();
}
[Key]
public int Id { get; set; }
[MaxLength(50)] //nvarchar(50)
public string TechName { get; set; }
public bool isDeleted { get; set; }
// Relation to Skills
public virtual ICollection<Skill> Skills { get; set; };
}
public class Skill
{
[Key]
public int Id { get; set; }
[MaxLength(50)] //nvarchar(50)
public string SkillName { get; set; }
public bool isDeleted { get; set; }
//Relation to Tech
public int TechId { get; set; }
public Tech Tech { get; set; }
}
控制器
[HttpPost]
[ProducesResponseType(typeof(Tech), 200)] //Specifind in the swagger the object your method receive
public async Task<ActionResult<Tech>> PostTech([FromBody] Tech tech)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
//Here you add the Tech in Techs table and all skills in the Skills table, no need separate save for skills
await _context.AddAsync(tech);
await _context.SaveChangesAsync();
return Ok(tech);
}
您收到的错误 400 意味着您的 json 数据无法反序列化为 Tech 对象。我在发送到
PostTech
的对象中看到,您在 "id": 3
中传递了 "techId": 3
和 Slill
,但是如果您使用代码优先方法 EF 创建 Id 作为身份,这意味着您必须将 Id
保留为 null 相同对于技能