I have created a very simple API, which adds "Opportunities" to my database. That works fine, here is my controller method:
[HttpPost("addopportunity")]
public async Task<IActionResult> AddOpportunityAsync([FromBody]Opportunity opp)
{
try
{
await _opportunitiesRepository.AddOpportunityAsync(opp);
return new OkObjectResult("Opportunity Created");
}
catch (Exception ex)
{
return new BadRequestObjectResult(ex.Message);
}
}
I now want to extend my Opportunity class to include a list of materials with the opportunity. Here is my (simplified) updated Opportunity class:
public class Opportunity
{
public long Id { get; set; }
public DateTime DateCreated { get; set; }
public virtual IEnumerable<OpportunityMaterial> MaterialList { get; set; } = Enumerable.Empty<OpportunityMaterial>();
}
And my OpportunityMaterial class:
public class OpportunityMaterial
{
public long OpportunityMaterialId { get; set; }
public long FkOpportunityId { get; set; }
public string MaterialId { get; set; }
public decimal Quantity { get; set; }
public decimal QuotedPrice { get; set; }
public decimal CompetitorPrice { get; set; }
public virtual Opportunity FkOpportunity { get; set; }
}
Finally the change to my dbContext:
public virtual DbSet<Opportunity> Opportunities { get; set; }
public virtual DbSet<OpportunityMaterial> Materials { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Opportunity>(entity =>
{
});
modelBuilder.Entity<OpportunityMaterial>(entity =>
{
entity.HasOne(d => d.FkOpportunity).WithMany(p => p.MaterialList)
.HasForeignKey(d => d.FkOpportunityId)
.OnDelete(DeleteBehavior.ClientSetNull)
.HasConstraintName("FK_Opportunities_Materials");
});
}
Now, when I submit a Post (I am using Swagger) I get the following error:
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "00-7e225c0f43c590e79d808df171998542-6b8ff60db4c321c6-00",
"errors": {
"opp": [
"The opp field is required."
],
"$.materialList[0].fkOpportunity": [
"The JSON value could not be converted to DataModels.Microservice.Models.Opportunities.Opportunity. Path: $.materialList[0].fkOpportunity | LineNumber: 24 | BytePositionInLine: 31."
]
}
}
I assumed that FromBody would be clever enough to deal with the child objects, or maybe it is and I am missing something else. Any guidance gratefully received.
****EDIT To try and fault find I added another POST to my controller to try to insert a Material on it's own. Here is the JSON that Swagger gave me:
{
"opportunityMaterialId": 0,
"materialId": "string",
"quantity": 0,
"quotedPrice": 0,
"competitorPrice": 0,
"opportunity": {
"id": 1,
"dateCreated": "2023-05-03T08:51:04.927Z",
"monthString": "string",
"weekOpp": 0,
"status": "string",
"wonLostReason": "string",
"customer": "string",
"site": "string",
"county": "string",
"notes": "string",
"startDate": "2023-05-03T08:51:04.928Z",
"endDate": "2023-05-03T08:51:04.928Z",
"contactName": "string",
"yearOpp": 0,
"sourceNotExistingCustomer": "string",
"materials": [
"string"
]
}
}
To my very inexperienced eye, it looks like a bit of catch 22, so when it's putting in the Material, it is also trying to put in an Opportunity to go with it. This results in a similar error to the original one. Maybe this is how it's supposed to look and how EF handles the relationship, but I have clearly got something very wrong here.