C
C#•2y ago
dave1

ā” Struggling to delete a many to many relation

public async Task<IStatusCodeActionResult> Remove(long areaId, long houseId)
{
var area = await _context.Areas
.Include(s => s.Houses)
.FirstOrDefaultAsync(s => s.Id == areaId);

if (area == null)
return BadRequest("Area does not exist");

var house = await _context.Houses
.FirstOrDefaultAsync(s => s.Id ==houseId);

if (house == null)
return BadRequest("House does not exist");

var success = area.Houses.Remove(house);

if (success == false)
return BadRequest("House not found in this area");

_context.Areas.Update(area);

await _context.SaveChangesAsync();
public async Task<IStatusCodeActionResult> Remove(long areaId, long houseId)
{
var area = await _context.Areas
.Include(s => s.Houses)
.FirstOrDefaultAsync(s => s.Id == areaId);

if (area == null)
return BadRequest("Area does not exist");

var house = await _context.Houses
.FirstOrDefaultAsync(s => s.Id ==houseId);

if (house == null)
return BadRequest("House does not exist");

var success = area.Houses.Remove(house);

if (success == false)
return BadRequest("House not found in this area");

_context.Areas.Update(area);

await _context.SaveChangesAsync();
27 Replies
dave1
dave1OP•2y ago
been looking at it for a long time now, just need a sanity check if that's how it should be, then i must have fucked up somewhere else i think i'm going to just delete it manually, no idea how to debug this it's supposed to simply remove that sepcific house from the area, it's a many to many
Tvde1
Tvde1•2y ago
when you fetch the Area, you are not including the list of houses. Do that through
await _context.Areas
.Include(x => x.Houses)
.FirstOrDefault(...);
await _context.Areas
.Include(x => x.Houses)
.FirstOrDefault(...);
You would see that every area you fetch has no houses, if you omit the .Include
dave1
dave1OP•2y ago
sorry should have updated it, i have that in my current version now when i step debug through, i see it's removed it , i get no errors, but when i test the db after, that relation still exists
Tvde1
Tvde1•2y ago
_context.Areas.FirstOrDefaultAsync(s => s.Id == areaId);
_context.Areas.FirstOrDefaultAsync(s => s.Id == areaId);
will result into
SELECT TOP 1 *
FROM Areas
WHERE id == @areaId;
SELECT TOP 1 *
FROM Areas
WHERE id == @areaId;
and
_context.Areas
.Include(x => x.Houses)
.FirstOrDefaultAsync(s => s.Id == areaId);
_context.Areas
.Include(x => x.Houses)
.FirstOrDefaultAsync(s => s.Id == areaId);
will result into
SELECT *
FROM Areas a
WHERE id == @areaId
INNER JOIN Houses h
ON h.AreaId = a.Id
SELECT *
FROM Areas a
WHERE id == @areaId
INNER JOIN Houses h
ON h.AreaId = a.Id
dave1
dave1OP•2y ago
aye i'm presuming that the change tracker needs some change to track, so removing nothing, it cant track that change
Tvde1
Tvde1•2y ago
you can try
public async Task<IStatusCodeActionResult> Remove(long areaId, long houseId)
{
var area = await _context.Areas
.Include(s => s.Houses)
.FirstOrDefaultAsync(s => s.Id == areaId);

if (area == null)
return BadRequest("Area does not exist");

var house = area.Houses.FirstOrDefault(s => s.Id ==houseId);

if (house == null)
return BadRequest("House does not exist");

var success = area.Houses.Remove(house);

if (success == false)
return BadRequest("House not found in this area");

await _context.SaveChangesAsync();
public async Task<IStatusCodeActionResult> Remove(long areaId, long houseId)
{
var area = await _context.Areas
.Include(s => s.Houses)
.FirstOrDefaultAsync(s => s.Id == areaId);

if (area == null)
return BadRequest("Area does not exist");

var house = area.Houses.FirstOrDefault(s => s.Id ==houseId);

if (house == null)
return BadRequest("House does not exist");

var success = area.Houses.Remove(house);

if (success == false)
return BadRequest("House not found in this area");

await _context.SaveChangesAsync();
it makes one less db call and the update is not necessary, savechanges will save everything you change to entities
dave1
dave1OP•2y ago
oh you know, i have actually tried tha aswell hahaha i wasnt sure if it was required cheers, so ef context is doing more magic under the hood than i presumed, good to know
Tvde1
Tvde1•2y ago
yes, any entity you get from it will have its changes tracked (unless you explicitly tell it not to)
var area = await _context.Areas
.AsNoTracking()
.Include(s => s.Houses)
.FirstOrDefaultAsync(s => s.Id == areaId);
var area = await _context.Areas
.AsNoTracking()
.Include(s => s.Houses)
.FirstOrDefaultAsync(s => s.Id == areaId);
would make EF not track changes
dave1
dave1OP•2y ago
ah i had assumed it was on the action of Update/Create etc. it was tracking from that point
Tvde1
Tvde1•2y ago
honestly I'm not sure why your original code didn't work. It feels as if it should also work
dave1
dave1OP•2y ago
yeah you see i'm at that point aswell, i think i've fkd up the entities at least i know that side is fine cheers Tvde1, appreciated
Tvde1
Tvde1•2y ago
you think you messed up the entities?
dave1
dave1OP•2y ago
maybe, that's the only other moving part, or maybe my test is wrong oh god, i think it's the test
Tvde1
Tvde1•2y ago
😁 happens to the best of us
dave1
dave1OP•2y ago
yeah you helped me, cheers, hahah, in my test i'm creating the relation, then after hitting the endpoint i'm testing it again but i wasn't clearing the tracked values, i presumed once i saved async it was automatically clear šŸ¤¦ā€ā™‚ļø casual 4-6 hours in total time wasted on that
Tvde1
Tvde1•2y ago
I once spent 4 hours trying to figure out why my break point didn't get hit, turns out I was making HTTP calls to the test environment, not to my local api
dave1
dave1OP•2y ago
oh yup, done that, more than once or wondering why nothings working because i've left a break point somewhere
Tvde1
Tvde1•2y ago
everyone messes up like that, the trick is that your brain will remember and you'll check stuff much sooner
dave1
dave1OP•2y ago
and not noticed, though, not in c#
Tvde1
Tvde1•2y ago
then next time, a colleague asks you for help, you do the sanity checks and you save a lot of time
dave1
dave1OP•2y ago
i'm only like 5 days in .net oh, we're switching over to c#, i'm the canary
Tvde1
Tvde1•2y ago
well great job learning Entity Framework so far and making tests!
dave1
dave1OP•2y ago
new cto wants to move over, i figure, as long as its not my decision, i'm game, i like learning new systems/languages always tests, first thing i try and figure out how to do when learning a new thing xD it's strange how little literature there is around testing against a TestServer a lot of people saying to just mock EF w/e, but in making an API and basic crud i want to know something is stored.. testcontainers to the rescue anyway, no idea how i'm going to integrate that into the pipeline
Tvde1
Tvde1•2y ago
Integration tests in ASP.NET Core
Learn how integration tests ensure that an app's components function correctly at the infrastructure level, including the database, file system, and network.
Tvde1
Tvde1•2y ago
I have yet to dabble with actual integration tests like this
dave1
dave1OP•2y ago
i've got two sets one where i inject EF and wrap my tests in transctions, they're my integration the other is using TestServer, where it spins up an instance and i can tests the endpoint, where you cant use transactions, obviously cos it's a different process(coming from a scripting language took me a minute to realise this) a long minute, as once it's built ,it's built, i can't just use the code that's in the request so currently for those webapp tests it spins up a test container per class (testcontainers https://dotnet.testcontainers.org/) it disposes of them after, it's pretty nifty and i can test the system properly, end to end (without the front end) either way, cheers for the help, i was tearing my last few hairs out
Accord
Accord•2y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.

Did you find this page helpful?