Updating/Deleting owned properties with EF Core and AutoMapper
The problem I'm facing is that automapper is not tracking the changes since when i retrive AsNotracking() it wont change anything, but if i remove that, then it complains about the same entity being tracked when i do
mapper.map<Entity>(doman), which creates a new entity and EF begins tracking it, I solved it by fetching the entity in the repository and doing mapper.map(entity, domain) so it replaces the one i fetched, but in my command handler I already did the fetch of the entity and did an in place mapping to change its values, how can I avoid re fetching in my repository?
92 Replies
what's this in the context of?
are you updating an entity?
I am updating an entity, that has owned properties, if i did it the first way, then it wouldnt delete the old owned property
I have a code that is working but i dont like it
how are you actually updating the entity?
ctx.Update()
by chance?This right now works:
but see i do a call to get as tracking
ive tried setting the state to modified/deleted to the owned properties and it doesnt work
wait, so what exactly is the issue?
if that works, i don't really see a problem (aside from using the repository pattern on top of EF, but we can talk about that later)
generally the update pattern is fetch entity (as a tracking query), set entity properties, save changes
oh i see, maybe
the issue is that if i use the mapper to make a new entity, not like it is now
then it doesnt apply any changes
since it thinks its a new entity and begins to track it
the issue is that i do a get in the command handler
and another get in the repository
yeah i see that, two fetches
with automapper and repo on top of EF this is all kind of a mess
why are you (or by you, automapper) creating a new entity?
automapper does create an entity
if you only give it one argument
mapper.map<entity>(another entity) will result in a new entity
if you do mapper.map(entity1, entity2) it will override entity 1
post the code that you want to work
one second
why is this not a good idea? btw, should UnitOfWork be the way to do it?
yes, and an EF context is already a unit of work
this doesnt even update primitive properties
let alone owned ones
because the mapper creates a new entity that EF starts to track
also our arch is now, commands and queries, and those handlers have repositories that have the dbcontext access
i think you can make it work by something like
assuming mapper.Map sets the properties of entity1 from request
yeah but that still does 2 gets
one in the command handler
one in the repository
which is what i dont like
its a small nitpick i know
shouldn't there not be any data access in the command handler?
but i just wanted to know if it was possible
except through the repository
handlers have repositories
as properties
oh right
yeah this seems like an arch problem
you wouldnt have a repository pattern?
what would the handlers use?
because if
EditPayeeAsync()
takes a payee and not an entity that can already be tracked by EF, you're necessarily either going to create a new entity or fetch oneyeah repos take domain models
so there's no way you can edit a payee without adding a new one to the change tracker
i wont change it now but want to learn
what would be a good approach with the repo pattern and unit of work
with cqrs
just don't
inject the db context into your handler and do the work there
what a repository does here is take an EF context and restrict its API
which is now causing you problems because you want to edit a payee without adhering to the repository's implementation (i.e., taking a domain model and either mapping or fetching)
here's how my kind of update handler looks https://github.com/MarkusG/sst/blob/main/api/Sst.Api/Features/UpdateTransaction/UpdateTransactionCommand.cs
ignore the category logic and it's just
should handlers have access to the dbcontext?
yeah
oh you use rawsql
for that query specifically
oh okay
also i worked on another project in next
because i want to avoid a race between getting the max and doing the insert
that had an ef core copy
where we had readonly repos
and write only repos
commands and queries would have those
and also have domain and entities
yeah that seems like overkill to me
typically people here recommend $vsa
its the second time i use cqrs
the last link there is a good talk on it
i like it because a lot of separation of concerns
we used services before
it was a mess
like genericservice that had dbcontext in them
yeah i started with that as well
then it caused me a bunch of pain
so all the repositories would be gone
and just add entire db context to the handlers
but wouldnt then you have access to all dbsets in any handler
yeah
is that safe?
define safe
well youre right
it's necessary for a handler with cross cutting concerns
thjat in any repo
i also have all db sets
available to me
yeah exactly
it's just an extra layer of abstraction you don't need
you have access to all repositories in your handler if you inject them
no difference between
and
youd do something like this
i would need to add a mapping profile between the command and the entity tho
i posted what i'd do
but if i do a lot of gets of entities, where would i put that repeated code?
forget automapper, forget repositories
fetch, update, save
what repeated code?
payees.FirstOrDefault(...)
?the firstordefault
yes
is there something wrong with repeating that
you said no repositories tho, or i misunderstood you
yeah i know that repeated code is okay, but repeated intention is not
and the intention is to fetch an entity
there i'm just pointing out the lack of a difference between repos and no repos in the context of what the handlers "have access to"
so to me, thats bad
but what do you gain by tossing that
FirstOrDefault()
call into a repository method and then calling that method instead
you still call the same method and pass the same IDsnot saying into a repository
but some other place
you could make an extension method on
DbSet<PayeeEntity>
if you wantyeah that could work
because i tried messing up with ef core, state modified, state deleted, get entry properties, get entry proprerties as objects, and couldnt get it to work
you mean like messing with the change tracker yourself?
youd do something like that?
yeah i tried a lot, and nothing worked
no, i wouldn't
but would it be like that if i were to use extension methods
i would just write
FirstOrDefault(...)
everywhere i need to get an entityi know you said you would repeat
the code
i can't give you an opinionated answer on how to do something that i wouldn't do in the first place
i understand
but thanks for all the inputs
i will just live with the fetching twice
sure thing
gets kinda worse in here tho
i started out with CA and repositories and services and all that stuff
but it caused so much pain and now that i use VSA everything is just way simpler
there's much less thinking about where X should live and what Y's responsibilities are
i didnt start this project, was passed it down to it as tech lead so just gotta follow what it is, cannot change a lot of stuff
that's always fun
godspeed
some stuff i tried haha
thank you friend
sure thing!
also uhm how would you handle applying filters?
.Where()
yeah but now i got a bunch of ifs
haha
that's big indeed
but, if you're filtering on a lot of different things then it's not wrong
might be able to get rid of the ifs by using
.Where(x => filterProp == null || x.FilterProp == FilterProp)
yeah it depends on a lot of stuff
then the
Where()
is just a Where(true)
if you're not filtering by that thingvar filters = new List<Expression<Func<PayeeEntity, bool>>> creating something like that would work? then executing the where of all the ones that arent null?
uhh you mean like
?
you could
pointless though imo
you've still got all the if statements
no matter what you do, you'll always have to check if you're filtering by each thing
so just let the code be long
yeah i gues it is
Unknown User•23h ago
Message Not Public
Sign In & Join Server To View