Ingus Skaistkalns
Ingus Skaistkalns

Reputation: 33

How and where to validate uniqueness of attribute/property in ASP.NET Core MVC using Entity Framework Core 6

I want to check, that users table records does not have specific email already stored.

If there is, then ModelState.IsValid returns false in controller action.

I understand need of unique constraint and I understand issues with race conditions. Those are not my concern right now.

At this point I just want to make ModelState.IsValid to return false after querying data in right place and making model invalid.

Should I implement such validation:

  1. in DbContext?
  2. in my entity classes (User / Company etc.)?
  3. in SomeCustomValidation class?
  4. directly in controller (since there I can already query the database...)
  5. somewhere else...

And nice bonus would be create solution reusable across all entities :)

How should I do it?

Upvotes: 3

Views: 3372

Answers (2)

Rena
Rena

Reputation: 36645

You can custom validation attribute like below:

public class TestEmailAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(object value,
        ValidationContext validationContext)
    {
        var context = (YourDbContext)validationContext.GetService(typeof(YourDbContext));
        if(!context.User.Any(a=>a.Email==value.ToString()))
        {
            return ValidationResult.Success;
        }
        return new ValidationResult("Email exists");
    }
}

Model:

public class User
{
    public int Id { get; set; }
    [TestEmail]
    public string Email { get; set; }
}

View(Test.cshtml):

@model User
<form method="post" asp-action="Test" asp-controller="Home">   
    <div class="form-group">
        <input asp-for="Email" />
        <span asp-validation-for="Email" class="text-danger"></span>
    </div>

    <input type="submit" value="Post"/>
</form>

Controller:

//GET render the Test.cshtml
public async Task<IActionResult> Test()
{
    return View();
}
[HttpPost]
public async Task<IActionResult> Test(User user)
{
    if(!ModelState.IsValid)
    {
        return View(user);
    }
    return RedirectToAction("Index");
}

Upvotes: 4

mostafa khoramnia
mostafa khoramnia

Reputation: 197

better way is that you check it before every insert or update by :

if(db.Table.Any(x => x.UniqueCloumn == newValue))
    error = "this record is already exist"
else
{  
    db.Table.Add(newObject);
    db.Savechanges() 
}

also there is some approach for reusable code that I do not recommend : https://www.codeproject.com/Tips/1143215/Validate-a-Unique-Constraint-at-dbContext-Validate

Upvotes: 0

Related Questions