First, let's look at rewriting the attribute...
public override bool IsValid(object value)
{
var db = new CoinDataContext();
//Return whether none of the email contains the specified value
return db.Emails.Count(e => e.Email1 == value.ToString()) == 0;
}
Also, there was no need to cast (c == 0)
as a boolean, as the result of that operation is already a bool. And the type bool
is an alias for Boolean
in the same way that int
is an alias for Int32
. Either is acceptable. I prefer the lower case version myself.
As Alex has already suggested in his answer, this wouldn't be a sure way of determining whether the email address was unique when it goes into the database. Only that it's unique at the time of checking.
Finally, and a bit off-tangent... I have written some linq extensions such as the following class. Using it would allow me to rewrite the return on the attribute to db.Emails.None(e => e.Email1 == value.ToString());
. This makes it a little bit more readable.
Update
There isn't a way of determining the uniqueness of a value in the database without going to the database and comparing the rows against the values written. You still need to create an instance to the database. What I would do though is look at seperating these concerns into areas such as a service layer and a data layer (separate projects from the MVC website project). Your data layer would exclusively handle anything to do with the database. If you'd like I can write some examples of how you'd separate the CoinDataContext from the attribute itself?
Addressing another of your concerns, here we remove the need for the query inside the attribute, but you still need a call to the database, and specifying which table you want to use.
Because this is an attribute however, I'm not 100% sure if you can use linq lambda expressions in the attribute it, so your attribute has to remain generalised in this fashion.
Data layer project
This layer would contain different classes relating to different tables. The class below is dedicated to the email table.
Email Mapper class
public static class EmailMapper
{
public static void IsValid(Func<string, bool> query)
{
var db = new CoinDataContext();
return db.Emails.Count(query) == 0;
}
}
Service layer project
This layer is responsible for general validation of objects, but also is used for going to other layers such as external APIs.
EmailService class
public static class EmailService
{
public static IsValid(string address)
{
bool isValid = false;
//...Check email is valid first with regex. Not done.
isValid = RegexHelper.IsEmailAddressValid(address);
//Go to the database and determine it's valid ONLY if the regex passes.
return isValid ? EmailMapper.IsValid(x=> x.Email == address) : false;
}
}
Attribute class in web project
public override Boolean IsValid(Object value)
{
return EmailService.IsValid(value.ToString());
}