Prevent Duplicate Users
Reading
Avoid duplicate email addresses
To make the email unique, we can add a unique index on the field. Indexes are
a database optimization technique that allows the database to have fast access
to looking up information based on a specific column. We automatically get an
index on our Id
column to make those lookups fast. Most of the databases we've
worked with so far haven't been so extensive that indexes aren't needed to make
them fast. However, we are going to use them here to enforce uniqueness.
When creating an index, we specify the columns involved. Selecting the columns makes lookups for values in those columns fast. Of course, creating an index takes up more space in our database. It also makes inserting data slower since it needs to insert data into our table and update the index information.
One of the aspects we can make of an index is to specify that for the column, or columns involved that the values be unique.
To create our unique index, we will add some code to our DatabaseContext
model.
protected override void OnModelCreating(ModelBuilder modelBuilder){modelBuilder.Entity<User>().HasIndex(user => user.Email) .IsUnique();}
Then we will generate a migration:
dotnet ef migrations add AddUserEmailIndex
Then run the migration:
dotnet ef database update
If we attempt to create a user with a duplicate email address, we will get an exception in our controller. To handle that, we will catch the exception and instead of terminating the request, we will send back a custom error message:
[HttpPost]public async Task<ActionResult<User>> PostUser(User user){try{// Indicate to the database context we want to add this new record_context.Users.Add(user);await _context.SaveChangesAsync();// Return a response that indicates the object was created (status code `201`) and some additional// headers with details of the newly created object.return CreatedAtAction("GetUser", new { id = user.Id }, user);}catch (Microsoft.EntityFrameworkCore.DbUpdateException){// Make a custom error responsevar response = new{status = 400,errors = new List<string>() { "This account already exists!" }};// Return our error with the custom responsereturn BadRequest(response);}}
Since we are generating the error in the same format as validation errors, we will get a nice error in the UI when someone attempts to use an email address that exists.