Preparing Models for an API (How to setup relationships)
Hey fellows!
I wonder how to set the properties for related models ...
Here is my model:
Thank you for your help.
101 Replies
This is fine, if you want a fully mutable entity
I'd highly recommend adding foreign key properties to the models thou
Ie
public int UserId ...
could you explain how to create foreign key props?
Just have it be the same type as your Id prop in the other models
nice.
would this be cool?
Yep.
If you want to set the relations via a constructor, include two constructors
One for models and one for just ids
what do you mean?
how would they look like?
I'm on mobile ATM so don't really want to type out code :p
oh ok
But two identical constructors, one with complex objects for the relations, and the other with only IDs for those relations
All non-nav props set in both constructors
why would I do this?
Because otherwise you get issues 🙂
uh. I don't get it yet. 😦
Ef will use the is constructor internally, even if it's private
Id*
aaaaand in general: How to type out 2 constructors?
Just make two :p
I'm not sure I'd use primary constructors for this either
However, you can also skip ctors entirely, since your models are fully externally mutable
All your setters are public
what does that mean?
Do you not understand access modifiers?
I do.
Public Vs private etc
I understand.
Okay, then I don't understand the question
mmmh. sorry
I understand now.
What I personally prefer to do is...
* Mostly private setters
* Private EF constructor with IDs
* Public ctor for my own code to use
I am just starting out. Am open for everything.
The only thing unique to EF is that you must have a setter for any prop that should be database tracked, but it can be private
yeah, ok.
And that EF can't set navigation properties from a constructor
yes, I experienced that already
That's why you need a constructor with the ids
maybe you can post a code snippet later?
Sure
~ 45 mins or so
would be great
I'd probably have the nav props be
private set
too, as for the Ids, to be honest 😛Hooo, thanks, master.
just one thing: "private member is not used" ...
member: private Comment.Comment ....
?
Oh, you have some analyzer that says the private constructor isnt used
downsides of static analysis, it doesnt take ORMs and reflection into account 🙂
EF can and will use that private constructor.
you can comment it out and your program wont work, or have it and it will work
Well, I have to admit: You are my hero of this day. 😉 Thank you soooo much.
now the puzzle in my head fits together
np
its a bit weird at first, with how EF can use private setters/ctors, and how it populates the values as needed when you do selects etc
Pob's EF tips:
* Don't use repositories over EF! Use the context, and almost all queries should include a
Select
!Since I started using required properties, constructors seem like bloat lol
Have not yet started messing about with required on entities tbh
doesnt help that we have audit trails on most of our entities
The non-nullable property "User" must contain a value not equal to NULL upon exiting the constructor. Consider declaring the "Property" as nullable.
The non-nullable property "Post" must contain a value not equal to NULL upon exiting the constructor. Consider declaring the "Property" as nullable.
UUUUH. What should I do?
I get these messages
you removed the nullability on the props I guess?
yes, as you told me ! 😉
hah yep
yeah, so, there are a few ways to get around it
the quick and dirty is to set them to
= null!
uh
and the other one?
are there any downsides using
= null!
use a nullable backing field for the prop and throw when accessed if its null
?
well, you do get nullability problems when using the entity "outside" of EF queries
if you fetch it without including the nav prop, it will be null regardless - but your type indicates that its not possible. not a very nice error.
but you also dont want to be forced to always include the nav prop, that makes queries much slower
I guess a decent workaround is to have it be non-nullable in the constructor, but nullable on the property. combine that with a private set and you should be fine
or no, you wont actually
nvm that. the migration would generate wrong
thank you!
have a good time, bye!
The message:
what can I do about it?
Provide the required values...?
I thought i have done it with
newPost.Blog = blog
??Your action method takes a
Post
from the request body
So it expects all properties of that post, that are not nullable, to be filled
If you want to set some properties later, or if you want the form to not send all of the properties of a post, use a DTO class
One that only has the properties required
Based on that, you can then create the actual postoh, thanks.
what's a DTO class?
Data Transfer Object, meaning a class whose sole purpose is to be a container for data
It has no code besides properties, basically
for example
thanks.
sealed
? what's that?It means the class cannot be inherited from
ok
Warning for UserData ...
Argument "1": Conversion of "Textopia.Models.UserData" to "Textopia.Models.User" not possible.
this is the DTO classWell, yeah
(don't use
AddAsync
btw)why not use async?
It's used only for very specific edge cases
good
As it does no database IO, it doesn't need to be asynchronous
Only
.SaveChangesAsync()
actually calls the db, so this one does need to be async
Regardless, you will have to map the data from your DTO to your actual database model
(also, I'd remove the primary constructor from the DTO, it's not needed, properties alone are fine)My code analyzer complains if I remove the Asnyc from AddAsync !
Do you still await it?
yap
Don't
good
It's not asynchronous, it doesn't need to be awaited
the same with "FirstAsync" ?
No, this one calls the database
So it needs to be asynchronous
uh then ... ok
Only Add/AddRange/Delete/DeleteRange/Update should be non-async
how to translate DTO to Model ?
Either manually, or with something like
Riok.Mapperly
Manually is fine
can you help me with this?
or should I reach out to the internet ?
Manual example:
Do I have to create another constructor in the model?
because:
just another error message
As you will observe in my code, it does not use any constructors
Instead, it makes use of
required
propertiesnow I see
would DTOs work WITH constructors, as I rely on them?
this is all I have.
chatGPT suggests this:
what do you think?
absolutely not
the entity should not be aware of the DTO existing
mmh then what?
static methods on the DTO
FromEntity/ToEntity
if anything
I guess ToEntity wont be a static method thouuh I understand
How do you rely on constructors for DTOs, if you never instantiate that incoming DTO yourself?
ASP binds form values to it
You never touch the ctor
I don't understand you.
You never create an instance of
MyCoolDto
It should not matter for you, whatsoever, whether it has a constructor or not
So I wonder, why are you "relying on them"I have created a whole project with constructors.
So?
Use them when they're useful
Don't use them if they're not
could you help me with my DTO ?
I did
I know
but not the way I desired
remove
static
from ToUser and just do return new User(... data from dto here...)
also, most of the time you have separate DTOs for in and out. in fact, you might have several "out" dtos for a single entity
it all depends on what data you need for what endpoint in your api
Here
can I use required props in UserData AND not use them in my models?
No, once you ever type
required
anywhere you must use it for every property, otherwise the compiler will hijack your microwave and explode it
You can, of course you can
If you're dead-set on using constructors and suffering headaches that go with that decision, sureI am just new to the whole thing.
You can even use a constructor here, if you love writing a lot of useless code
In general, though, remember that language features are tools
You use them when they're needed
And don't use them when they're not
You don't see people trying to cut wood using a screwdriver because they're committed to using a screwdriver for their project
They probably set the screwdriver aside and pick up a saw
When to use "record"s in C# ?
... btw
Ah, a very good question! Records would be ideal for DTOs, actually
They're immutable, which makes sense for a DTO since you don't want to be modifying the incoming data
The syntax is also super short, so your DTOs can even exist next to actions or handlers, no need for separate files
They also offer some nice stuff like value-type comparison or desconstruction
k. 😦 I just dont understand how to translate DTO to Model.
Or, if
Model
has a constructor,
Or, with a ToModel()
method on the DTO,
so... Now I understand.
Thank you very much
and have a good time, ZZZZZZZZZ ...