EFCore Collection Trying to save a duplicate.
I'm building a dotnet maui app, and when I try to save a
Rental
with a ICollection<Equipment>
to my database, it errors saying that the equipment already exists.
Here's the models:
Equipment:
Here's the code that saves it:
At a break point at the createdRental == null
line, it shows that there are two equipments in the List.
It then throws an error on the db.SaveChangesAsync()
line. I think I just need a way to tell EFCore to not save the elements in the list, but to just create a link to them from the Rental im trying to save.45 Replies
Are you trying to create or update a rental?
Only create
should the syntax then not be db.rentals.add()
Same error if it's add()
what is the error because in the screenshot i see instance already tracked but i cant fully read it
The full error says that the Equipment.id already exists in the database, which is true, it does already exist
you want to add the equiment when adding the rental i assume
No, I just want the rental to link to existing equipment. The equipments are already made and created, and then the rental should just contain existing equipments
ye I understand I recommend retrieving the equipment form the db and then adding it i you give me a sec I can make a query
That error isn't telling you it already exists. That error is telling you that another
DbContext
has loaded that specific Equipment
entity and is already tracking it. An entity can only be tracked by a single instance of DbContext
at a time.ye i also saw that if that persists you can call changetracker.clear()
Could also mean they aren't properly disposing of their
DbContext
s or have queries tracking entites that should not be.Oh ok
(I'm definitely not disposing properly I'll have to do that)
thanks
true youre probably doing something wrong if you randomly get that
What do your EF queries look like?
yep
i mean show code of your EF queries, lol
as you are probably setting every query to track entities
and if you have read-only queries, you should be using
AsNoTracking()
I'll send em here in a minute
But i def have multiple DbContexts, how do i dispose of those
show your controller / service code first
need to see how you're using everything
Sure
When I'm grabbing entities I don't need em sorted or anything I just do db.Equipments.ToList();
Or you use EF as intended and do
.Include(cr => cr.Equipment)
as part of your query and it'll populate it automatically.
that means you are loading and tracking every single Equipment
instance, which is bad.oh ok
Here, lemme show you
This is my Rental razor page.
All the other pages are similar to this
@ded
first thing that jumps out at me is you're not using DI for any of this
since you're using razor pages I assume this is MAUI with Blazor?
yep
then my first suggestion is to look through this razor tutorial on how to set up your pages and use codebehind https://learn.microsoft.com/en-us/aspnet/core/data/ef-rp/intro?view=aspnetcore-8.0&tabs=visual-studio
Razor Pages with Entity Framework Core in ASP.NET Core - Tutorial 1...
Shows how to create a Razor Pages app using Entity Framework Core
not sure how much is applicable since I don't use maui or blazor myself
ok, thanks no worries
as for your queries and code, I wouldn't make a single datacontext like this
instead I would do something like
using
will implicitly dispose of something once whenever the enclosing scope exits, so in this case it will dispose of the context when DeleteRental
exitsAh ok, that makes more sense
What would be a better way of grabbing all of the data?
you should also be able to replace
db.Rentals.Remove(db.Rentals.First(p => p.Id == id));
with db.Rentals.Remove(new Rental { Id = id })
, that way you can delete without loading entities from the databaseOk
can you show the page that query is in?
Its there, in the foreach, not in the code
oh, didn't see that
lol
ok yeah that's gonna track every customer and equipment that is rented out
which is not something i need to do, i just wanna grab em all
you can add
.AsNoTracking()
at the beginning of your queryOk cool
So what im understanding is that each DataContext should really only be used for like one or two operations and then disposed of?
generally speaking, yes, a
DbContext
should be considered a single unit of workOk cool
if you want to only load the data you need, you can do that by using
Select
within your query
but properly tracking / not tracking your entities is a good place to start, should help get rid of your errorsJust finished changing everything over, lemme try it rq
Works now lmao
thanks
i have learned more about efcore from this, very epic 👍
:PepoSalute: