C
C#•4d ago
Aiyoh

EF attributes vs built-in C# keywords (like required). Differences and when to use?

Essentially what the title says. In this code
using System.ComponentModel.DataAnnotations;

namespace Easygym.Domain.Entities
{
public class User
{
[Key]
public string? Id { get; set; }
[Range(1, 50)]
public string? Name { get; set; }
[EmailAddress]
public string? Email { get; set; }
[MinLength(8)]
public string? Password { get; set; }
[Required]
public string? Role { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.Now;
}
}
using System.ComponentModel.DataAnnotations;

namespace Easygym.Domain.Entities
{
public class User
{
[Key]
public string? Id { get; set; }
[Range(1, 50)]
public string? Name { get; set; }
[EmailAddress]
public string? Email { get; set; }
[MinLength(8)]
public string? Password { get; set; }
[Required]
public string? Role { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.Now;
}
}
I'm not sure whether I need to add a [Required] tag to the Id or if [Key] makes that redundant, or if I need to make Id required with the c# keyword. I've researched this and what I've found is that the required keyword is checked at compile time while the attributes from EF are checked during runtime and they're what's being used for validation etc. The obvious question I have is to always use required attribute where I use the keyword in c#, or vice versa? Another example here is that my Role will always be defined. I have the [Required] attribute for validation. But do I need to add the required modifier as well?
130 Replies
Angius
Angius•4d ago
Nullable type -> non-required Non-nullable type -> required public int Id { get; set; } will generate a NOT NULL in the db public int? Id { get; set; } will not
Aiyoh
AiyohOP•4d ago
in my case the Id is a string so its nullable by default? I mean it wont be nullable but I get the warning that it might not be set But I know it will be set
jcotton42
jcotton42•4d ago
It's string?, which is nullable.
Angius
Angius•4d ago
Depending on .NET version and whether you disabled NRTs
jcotton42
jcotton42•4d ago
use = null!; to suppress that.
Angius
Angius•4d ago
Nowadays, by default, string is non-nullable
Aiyoh
AiyohOP•4d ago
What's the difference between that, required and [Required]
Angius
Angius•4d ago
required has you set this property
class Foo
{
public required int Bar { get; set; }
}

var f = new Foo(); // error
class Foo
{
public required int Bar { get; set; }
}

var f = new Foo(); // error
jcotton42
jcotton42•4d ago
EF doesn't look at required. Non-nullable with NRTs on means the same as [Required]. = null!; isn't looked at by EF, it just shuts up the compiler.
Angius
Angius•4d ago
[Required] is just an annotation for EF, validation, etc. Was useful before NRTs
Aiyoh
AiyohOP•4d ago
Whats NRTs let me google
jcotton42
jcotton42•4d ago
nullable reference types the ? on classes like string
Aiyoh
AiyohOP•4d ago
So if non nullable with NRT enabled which in my case it is, means the same as [Required[ I don't need to add that attribute?
jcotton42
jcotton42•4d ago
yes
Aiyoh
AiyohOP•4d ago
This is what dumbass chatgippity told me The compiler forces you to provide a value when creating an object. Does not prevent null values at runtime (e.g., database validation).
Angius
Angius•4d ago
Kinda-sorta For backwards compatibility reasons, NRTs in C# were implemented... eh, so-so
Aiyoh
AiyohOP•4d ago
But jcotton just said that having required as a modifier is the same as [Required] in my case?
Angius
Angius•4d ago
The IDE will tell you "can't have a null there!" But it technically can be null
jcotton42
jcotton42•4d ago
I said EF doesn't look at it.
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
guid
Angius
Angius•4d ago
That's also a good question lmao System.Guid
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Angius
Angius•4d ago
Be the change you want to see, make a tag 😛
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
Doesn't matter for now, this is just a uni project
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
I'm a frontend dev, im shit at backend dont test me
Angius
Angius•4d ago
Unless your data is distributed across multiple databases and IDs need to be unique across them all Then GUIDs can be useful
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
wont make any difference in my case at all but ill change it
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
but im still confused as to what to use, required or [Required], or both?
Angius
Angius•4d ago
Neither Use a non-nullable type
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
jcotton42
jcotton42•4d ago
Again, EF does not look at required. erm, no [Required] impacts the db schema.
Aiyoh
AiyohOP•4d ago
Wym neither, how would i do validation then without manually checking for each null value?
Angius
Angius•4d ago
public int Foo { get; set; } is sufficient to generate INT Foo NOT NULL
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Angius
Angius•4d ago
And that Foo cannot be null
jcotton42
jcotton42•4d ago
By using string instead of string?, EF sets up the db schema as NON NULL.
Aiyoh
AiyohOP•4d ago
this is my user controller
using Easygym.Domain.Entities;
using Easygym.Infrastructure.Repositories;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Easygym.Domain.Constants;

namespace Easygym.Api.Controllers
{

public class UserController : Controller
{
private readonly IGenericRepository<User> _userRepository;

public UserController(IGenericRepository<User> userRepository)
{
_userRepository = userRepository;
}


[Authorize(Roles = Role.Admin)]
[HttpGet]
public async Task<IActionResult> GetUsers()
{
var users = await _userRepository.GetAllAsync();
return Ok(users);
}

[HttpGet("{id}")]
public async Task<IActionResult> GetUser(string id)
{
var user = await _userRepository.GetByIdAsync(id);
return Ok(user);
}

[Authorize(Roles = Role.Admin)]
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteUser(string id)
{
var user = await _userRepository.GetByIdAsync(id);
if (user == null)
{
return NotFound();
}
await _userRepository.DeleteAsync(user);
return NoContent();
}

}
}
using Easygym.Domain.Entities;
using Easygym.Infrastructure.Repositories;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Easygym.Domain.Constants;

namespace Easygym.Api.Controllers
{

public class UserController : Controller
{
private readonly IGenericRepository<User> _userRepository;

public UserController(IGenericRepository<User> userRepository)
{
_userRepository = userRepository;
}


[Authorize(Roles = Role.Admin)]
[HttpGet]
public async Task<IActionResult> GetUsers()
{
var users = await _userRepository.GetAllAsync();
return Ok(users);
}

[HttpGet("{id}")]
public async Task<IActionResult> GetUser(string id)
{
var user = await _userRepository.GetByIdAsync(id);
return Ok(user);
}

[Authorize(Roles = Role.Admin)]
[HttpDelete("{id}")]
public async Task<IActionResult> DeleteUser(string id)
{
var user = await _userRepository.GetByIdAsync(id);
if (user == null)
{
return NotFound();
}
await _userRepository.DeleteAsync(user);
return NoContent();
}

}
}
Angius
Angius•4d ago
If it cannot be null don't make it nullable There Your validation
Aiyoh
AiyohOP•4d ago
I just started with the project i have no error checking yet dont diss me
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Angius
Angius•4d ago
One thing at a time lol
Aiyoh
AiyohOP•4d ago
but i get that warning, should i just supress it with required or =null!
jcotton42
jcotton42•4d ago
= null!;
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
jcotton42
jcotton42•4d ago
required would force you to set it when creating it in C#, which doesn't make sense for a key your database will generate.
Aiyoh
AiyohOP•4d ago
man youre not really helping out by just trying your best to make fun of me
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Angius
Angius•4d ago
For database models, = null!; For DTOs, ViewModels, regular classes, required
Aiyoh
AiyohOP•4d ago
hm currently its a string so i generate it but i guess ill run a migration after changing ot int alright Whats a ViewModel?
jcotton42
jcotton42•4d ago
@Aiyoh the db already exists? and you already have migrations?
Angius
Angius•4d ago
An object you pass from controller to view
Aiyoh
AiyohOP•4d ago
Im not sure if thats connected to the mvc?
Angius
Angius•4d ago
It is
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
im running this as an api i have react on the frontend
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Angius
Angius•4d ago
Not MVC then
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
Thats why i have no idea what that is Wym
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
It exists but it's a local sqlite db
jcotton42
jcotton42•4d ago
Tebe, one thing at a time please.
Aiyoh
AiyohOP•4d ago
How? This is my Controller, the one im inheriting from
using Microsoft.AspNetCore.Mvc;

namespace Easygym.Api.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class Controller : ControllerBase
{
}
}
using Microsoft.AspNetCore.Mvc;

namespace Easygym.Api.Controllers
{
[ApiController]
[Route("api/[controller]")]
public class Controller : ControllerBase
{
}
}
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
I assumed attributes can be inherited Which is true right since I can access the api by api/controller
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Angius
Angius•4d ago
There was some confusion, because Controller is a built-in class that lets you return views But since it's your own class, it's fine
Aiyoh
AiyohOP•4d ago
Ah I called it Controller cuz its my own class didnt know what else to call it GenericController :harold:
Angius
Angius•4d ago
Eh, it's fine Maybe BaseController or something But Controller is fine
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
Alr so from now on I'll do everything non-nullable that needs to be not null with the null! thingy
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
Yeah yeah I was about to do that now
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
So wait if I do this like so : public string Role { get; set; } = null!; then whats the point of the [Required] attribute Should I never use it
jcotton42
jcotton42•4d ago
It existed before null ref types.
Aiyoh
AiyohOP•4d ago
Ahh
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
So null reference types are something new in c# ?
Angius
Angius•4d ago
And nothing ever gets removed from .NET/C# Somewhat new, yes
jcotton42
jcotton42•4d ago
Since C# 8, we're currently on 13.
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
Damn I thought this attribute was something new, but it was something old cuz the docs I went through on microsoft docs were using this
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
i watched a course on .net and the guy turned it off, i kept it on cuz theres no way its better with it turned off
jcotton42
jcotton42•4d ago
They explicitly disabled NRTs?
Aiyoh
AiyohOP•4d ago
the more you know
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
yes because he said that it might confuse a beginner but im not a beginner per se, only a beginner on the backend
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
i come from javascript land and i know how important it is to guard against null/undefined behavior
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Angius
Angius•4d ago
So, Javascript? :when:
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
when setting up the frontend for this project, i set up the strictest possible configs so the guy thats working with me (we need to have a partner so im teaching him frontend) doesnt end up doing :any for everything
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
using System.ComponentModel.DataAnnotations;

namespace Easygym.Domain.Entities
{
public class User
{
public int Id { get; set; }
[Range(1, 50)]
public string Name { get; set; } = null!;
[EmailAddress]
public string Email { get; set; } = null!;
[MinLength(8)]
public string Password { get; set; } = null!;
public string Role { get; set; } = null!;
public DateTime CreatedAt { get; set; } = DateTime.Now;
}
}
using System.ComponentModel.DataAnnotations;

namespace Easygym.Domain.Entities
{
public class User
{
public int Id { get; set; }
[Range(1, 50)]
public string Name { get; set; } = null!;
[EmailAddress]
public string Email { get; set; } = null!;
[MinLength(8)]
public string Password { get; set; } = null!;
public string Role { get; set; } = null!;
public DateTime CreatedAt { get; set; } = DateTime.Now;
}
}
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
ill just remove the guid gen
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
In the auth service I check whether the role passed in is valid so it never gets created without a role
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
var passwordHash = BCrypt.Net.BCrypt.HashPassword(password);
var user = new User
{
Id = Guid.NewGuid().ToString(),
Email = email,
Password = passwordHash,
Role = role,
CreatedAt = DateTime.UtcNow
};
var passwordHash = BCrypt.Net.BCrypt.HashPassword(password);
var user = new User
{
Id = Guid.NewGuid().ToString(),
Email = email,
Password = passwordHash,
Role = role,
CreatedAt = DateTime.UtcNow
};
thjis is where its generated
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
the createdAt is redundant I know forgot to remove it noted
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
Yeah thats the part I understood by researching, i cant do this at compile time Good thing I asked early because I literally only have one entity currently adn thats the User
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
Yes But this is fine I'm not gonna deploy this to production of 10000 users
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
I have no idea Chat gippity persuaded me
jcotton42
jcotton42•4d ago
Generic repos can be useful, but not in combination with EF.
Aiyoh
AiyohOP•4d ago
So I dont need this at all
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
jcotton42
jcotton42•4d ago
EF already provides a much better one for you, DbSet<T>. The only reason to use a generic repo over EF is if you plan to switch away from EF, but that's... unlikely.
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
So I need a service called UserService where I'll have methods like GetUserByEmailAsync and Ill usee the DbSet thing
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
I think our uni wants us to have a certain pattern like repository even though i didnt see the use of it
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
jcotton42
jcotton42•4d ago
are repos actually in the requirements?
Aiyoh
AiyohOP•4d ago
this is too much info for me ive literally used aspnet apis for 3 days max no but we need to use some sort of a pattern thats common I think its safer to have repository like this since everyone does it, but I'll keep in mind that its not the best approach here everyone does it like this at my uni* the course I watched used the CQRS pattern which I didnt quite get the benefit from He used the mediatr package No idea what the benefit was
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View
Aiyoh
AiyohOP•4d ago
No I was watching the course for 6-7 days but worked on the project for 3 days max So I ran the migration changed from string to int and I get datatype mismatch errors Is it possible to force the migration to delete all the records that cant be migrated? Or for example later if I get some issue and I need to run a migration for a change, how do I handle this without loss of data? I literally have one record in my users db, so I can remove it safely, but what if this happens later and I have 100+ records? Seems to have been an issue with sqlite (I had to manually change migration to delete id column then add instead of altering it)
Unknown User
Unknown User•4d ago
Message Not Public
Sign In & Join Server To View

Did you find this page helpful?