❔ Updating EF entity with object containing optional properties
I'm writing an API endpoint where you can pass in any number of parameters for an EF core entity. I then want to merge the given parameters/object into the entity to update only those fields.
I'm new to C# and having issues getting this to work. I ended up trying AutoMapper but it is updating all the given fields and setting the rest to null.
38 Replies
Any hints to push me into the right direction?
so you want to update only some fields of the whole entity, is that current?
the pattern i've been using is a DTO with every field nullable, and overwrite the entity properties with any non-null properties from the DTO
yes. say i've got an entity with 10 properties that i want to be updatable like this. I make a DTO with those 10 properties and theyre all nullable. i want to be able to make a request to update any number of those 10 properties on that entity
i just go through and check each one, i don't use a mapping library
and overwrite the entity properties with any non-null properties from the DTO
how do i do this part? i'm new to C#
so you just loop over the parameters?i just write it out, a loop would require reflection
oh. so you're hard coding the fields / checks
yep
mapping libraries are only really good for 1:1 mappings, as soon as you try to do something else it gets messy
seems kind of nuts to "hard code" all this stuff in like 3 different spots
like the model itself. then the dto. then all the checks on each field
figured there'd be a more elegant way
why are you doing it in 3 spots?
i do it in 2 but only because i have separate read and write models to maintain
i mean one of these models has like 25 properties. so i'm keeping a model, a DTO, and hard coded
if !== null
checks all in sync. just feels a little messy. i imagined that writing out the DTO and having .NET validate it, that my DTO would be a source of truth essentially. but i've got to check if those properties are all null anyways by hand
for example in TypeScript world, i'd probably validate the request object, filter out null values, then just apply the object and update iti mean, you could do reflection if you have a significant number of properties
then you also need a convention for indicating which DTO properties map to properties on other entities
or have the client send a DTO with all properties set, not just the modified ones
yeah... that's an option. i just liked the idea of only sending what needed to be updated, since it will usually only be one field anyway
i appreciate your help... i'm finding it difficult to google for answers in the C#/.NET world but it might just be my lack of knowledge
you're saying automapper wouldnt be a good use case for this though? i did try the following (not really certain what i was doing, but testing it out):
you need to figure out which properties have been updated and then set their states as updated
checkout ChangeTracker
it might work, i've avoided mappers in general
why would you do that manually?
the change tracker tracks changes automatically, that's the point
well its not perfect thats why, those nulls considered as updated
right, it doesn't solve the problem
it's not an EF problem, it's a matter of conditionally setting fields using some kind of indicator it has data to set
am i correct that C# doesn't have an
undefined
type? so essentially even if i "map" the object over, it still needs a value to map to (null or the actual value). so i suppose i'm saying that in my mapping, if the value is null, i need to grab the existing value from the entityC# is a strongly typed language, everything has a specific type
you could load the entity from the database, conditionally apply your DTO fields, then save it
you could use nullable fields and
null
as a flag for "don't change this field" or some other way to list which properties changedmakes sense. going to play around more. i really appreciate your help
this is how i've been doing it
in case you're not familiar with the null coalescing operator
??
it picks the left side if the left side is not null, otherwise the right sidethank you. i may end up just going that route for this proof of concept, but im interested in learning these other alternatives for my own knowledge as well
this. Get the entity from the db, then map your DTO into the entity (
mapper.Map(source, dest)
). Change tracking of EF will generate the right update query for you.
nested updates are messier and depend on what you want specifically
but yeah, that's not optimal if you've got only a couple of updated fields
since you'd be loading the whole entity from the dbi also end up with like 60 lines of this in my mapper profile... lol.
seems like more work than hand rolling the ampping
tbh
yeah it does. coming from typescript (and similar languages), it just seems crazy to me that theres nothing built in to do what i want here. but i guess i get it
so wasnt sure what i was missing
i did test that (used copilot to fill it in) but not entirely sure if thats even a good thing to do or not. i would also likely have to check and block certain columns from being updated.
i also tested creating an endpoint like
{id}/{columnName}
but ran into issues validating that the value matched the type of the column
though i did get the valid columnName
validation workingForAllMembers thing should work, the one from above
except for members that i have to override, like navigation properties, correct? i didn't see a way to set specific ones and then default to
ForAllMembers
for othersyou can ignore the navigation properties separately
or just specify MemberList.Source as a parameter to CreateMap
you don't have to make you navigation properties virtual unless you're using lazy loading btw
weird, every time i've tried to ignore those properties and then
ForAllMembers
, it doesn't work
figured the ForAllMembers overrides the ignoreactually there's a
ForAllOtherMembers
that doesn't exist anymore / was removed
but hate to go back and forth on this. just letting you know
you mean you don't want me to help?
no, of course i do. just don't want anybody to feel obligated - my last few responses have felt like i'm just shooting stuff down
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.