C
C#6mo ago
sspirit

✅ EF Core Relationship

I have 3 different models call Owner, Products and Warranty. The relationship between them is that Products can be created independently, so when a user purchase a product Owner table will have foreign key ProductsId inside it. During product purchase a new Warranty is created so OwnerId will be a foreign key in Warranty table. How do I declare this in model and the relationship at ApplicationDbContext? I'm having trouble due to wrongly created model and unable to submit the form from my Angular application. Model become more complex after implementing navigation property which now makes me unable to create a Owner
26 Replies
Angius
Angius6mo ago
product {
id
}

owner {
id
}

owned_items {
owner_id
product_id
}

warranty {
id
owner_id
product_id
}
product {
id
}

owner {
id
}

owned_items {
owner_id
product_id
}

warranty {
id
owner_id
product_id
}
? So owner should have List<Product> and List<Warranty> Product should have List<Owner> and List<Warranty> Warranty should have Owner and Product
sspirit
sspiritOP6mo ago
Yes but the problem with that is during my API Post call, it will complain the list of Owner cannot be empty inside Products.
No description
Angius
Angius6mo ago
What's doing the validation?
sspirit
sspiritOP6mo ago
I've handle in my controller to create a new unique serial number and create a new Warranty during the POST API call
No description
Angius
Angius6mo ago
No description
sspirit
sspiritOP6mo ago
I dont quite get it sorry. but I paste the response call that I got the error from. In my model I've created a list of Owners. but during Post API if the owner is not created yet how would I get the details to put in the list?
Angius
Angius6mo ago
I mean code What in code is validating that the list must not be empty?
sspirit
sspiritOP6mo ago
public class WarrantyDetail
{
[Key]
public int WarrantyDetailId { get; set; }
[DisplayFormat(DataFormatString = "{0:dd:MM:yyyy}", ApplyFormatInEditMode = true)]
public DateTime ExpirationDate { get; set; }
public string WarrantyStatus { get; set; } = "";
public ProductOwner? ProductOwner { get; set; }

}
public class WarrantyDetail
{
[Key]
public int WarrantyDetailId { get; set; }
[DisplayFormat(DataFormatString = "{0:dd:MM:yyyy}", ApplyFormatInEditMode = true)]
public DateTime ExpirationDate { get; set; }
public string WarrantyStatus { get; set; } = "";
public ProductOwner? ProductOwner { get; set; }

}
This productOwner inside Warranty model. Sorry not the list ones
Angius
Angius6mo ago
So it's not the product that's an issue? It's warranty?
sspirit
sspiritOP6mo ago
Yes, when a owner is created automatically in Warranty a new record is created in controller. But since this is related to navigation property I declared
public ProductOwner? ProductOwner
public ProductOwner? ProductOwner
for the one-to-one relationship
Angius
Angius6mo ago
I'm having trouble understanding You mean when a warranty is created, you also create an owner?
sspirit
sspiritOP6mo ago
When an owner is created a warranty then will be created. My ERD I think if i only implement the foreign-key there will be no issue, but now with navigation property it got me stuck. First time dealing with navigation property
No description
Angius
Angius6mo ago
So an owner cannot exist without warranty?
sspirit
sspiritOP6mo ago
[HttpPost]
public async Task<ActionResult<ProductOwner>> PostProductOwner(ProductOwner productOwner)
{
if (_context.ProductOwners == null)
{
return Problem("Entity set 'ApplicationDbContext.ProductOwners' is null.");
}

// Configure warranty expiration date and status
var warrantyDetail = new WarrantyDetail
{
ExpirationDate = DateTime.Now.AddYears(2).Date,
WarrantyStatus = "Active",
};


productOwner.ProductSerialNumber = await GenerateUniqueSerialNumberAsync();

// Query ProductDetail
var productDetail = await _context.ProductDetails.FirstOrDefaultAsync(pd => pd.ProductDetailId == productOwner.ProductDetailId);

if (productDetail == null) {
return BadRequest();
}


var newProductOwner = new ProductOwner
{
OwnerFirstName = productOwner.OwnerFirstName,
OwnerLastName = productOwner.OwnerLastName,
EmailAddress = productOwner.EmailAddress,
PhoneNum = productOwner.PhoneNum,
ProductSerialNumber = productOwner.ProductSerialNumber,
ProductDetailId = productOwner.ProductDetailId,
ProductDetail = productDetail,
WarrantyDetail = warrantyDetail
};

// Setting the reverse navigation property
warrantyDetail.ProductOwner = newProductOwner;
productDetail.ProductOwners.Add(newProductOwner);

_context.ProductOwners.Add(newProductOwner);
await _context.SaveChangesAsync();

return Ok(await _context.ProductOwners.ToListAsync());
}
[HttpPost]
public async Task<ActionResult<ProductOwner>> PostProductOwner(ProductOwner productOwner)
{
if (_context.ProductOwners == null)
{
return Problem("Entity set 'ApplicationDbContext.ProductOwners' is null.");
}

// Configure warranty expiration date and status
var warrantyDetail = new WarrantyDetail
{
ExpirationDate = DateTime.Now.AddYears(2).Date,
WarrantyStatus = "Active",
};


productOwner.ProductSerialNumber = await GenerateUniqueSerialNumberAsync();

// Query ProductDetail
var productDetail = await _context.ProductDetails.FirstOrDefaultAsync(pd => pd.ProductDetailId == productOwner.ProductDetailId);

if (productDetail == null) {
return BadRequest();
}


var newProductOwner = new ProductOwner
{
OwnerFirstName = productOwner.OwnerFirstName,
OwnerLastName = productOwner.OwnerLastName,
EmailAddress = productOwner.EmailAddress,
PhoneNum = productOwner.PhoneNum,
ProductSerialNumber = productOwner.ProductSerialNumber,
ProductDetailId = productOwner.ProductDetailId,
ProductDetail = productDetail,
WarrantyDetail = warrantyDetail
};

// Setting the reverse navigation property
warrantyDetail.ProductOwner = newProductOwner;
productDetail.ProductOwners.Add(newProductOwner);

_context.ProductOwners.Add(newProductOwner);
await _context.SaveChangesAsync();

return Ok(await _context.ProductOwners.ToListAsync());
}
In case this helps :/ or should I post the code else where Yes, because when owner purchase a product it should come with a warranty
Angius
Angius6mo ago
I'd start by using a DTO for the API instead of the database entity Since it's complaining that what you send to the API is incomplete... just use a DTO without the things that are unnecessary
sspirit
sspiritOP6mo ago
Correct me if I'm wrong so if a use DTO , my API call request body can be modified? I was in the assumption that all the columns in a table/entity should be made available in JSON Request body during an API call
Angius
Angius6mo ago
Only the things you want to send should be available in the request You wouldn't want the user to be able to set their own password hash Or their ban duration
sspirit
sspiritOP6mo ago
Understood ... :NotedHmm: so it should be a good practice to always use DTO so we can modify the API request body.. For example in my db i have an entity with columns of brand/model/color.. assuming the brand is created by default i should not showcase it in my request body, I create a DTO only for model/color ... Correct? haha
Angius
Angius6mo ago
It's always a good idea to use DTOs period API should receive and return DTOs Database models should never leave the app's boundary
sspirit
sspiritOP6mo ago
Ok got it, will update here if I able to restructure it successfully. Thanks for the help :feelscomfyman:
sspirit
sspiritOP6mo ago
@ZZZZZZZZZZZZZZZZZZZZZZZZZ Thankss man, restructure the code and created DTO. Now time to fix the rest of the methods with DTO too :sadcat:
No description
Angius
Angius6mo ago
Nice
sspirit
sspiritOP6mo ago
Anime reference cause saw your Youtube channel haha. Have a great day man. Arigato!
Angius
Angius6mo ago
Anytime :Ok:
Unknown User
Unknown User6mo ago
Message Not Public
Sign In & Join Server To View
MODiX
MODiX6mo ago
If you have no further questions, please use /close to mark the forum thread as answered
Want results from more Discord servers?
Add your server