まず、属性の書き換えを見てみましょう...
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;
}
(c == 0)
また、その操作の結果はすでにブール値であるため、ブール値としてキャストする必要はありませんでした。そして、型bool
は のエイリアスとBoolean
同じようにint
のエイリアスですInt32
。どちらでも構いません。私自身は小文字バージョンの方が好きです。
アレックスが彼の回答ですでに示唆しているように、これは、メールアドレスがデータベースに入ったときに一意であるかどうかを判断する確実な方法ではありません. チェック時に一意であるというだけです。
最後に、少し接線を外して...次のクラスなどのいくつかのlinq拡張機能を作成しました。これを使用すると、属性の戻り値を に書き換えることができますdb.Emails.None(e => e.Email1 == value.ToString());
。これにより、少し読みやすくなります。
更新
データベースにアクセスして、書き込まれた値と行を比較せずに、データベース内の値の一意性を判断する方法はありません。データベースにインスタンスを作成する必要があります。私がすることは、これらの懸念をサービス層やデータ層などの領域に分離することです (MVC Web サイト プロジェクトとは別のプロジェクト)。データ層は、データベースに関係するすべてを排他的に処理します。よろしければ、属性自体から CoinDataContext を分離する方法の例をいくつか書いていただけますか?
別の懸念に対処するために、ここでは属性内のクエリの必要性を取り除きますが、データベースへの呼び出しと、使用するテーブルの指定が必要です。
ただし、これは属性であるため、属性で linq ラムダ式を使用できるかどうかは 100% 確信が持てないため、属性はこの方法で一般化されたままにする必要があります。
データレイヤー プロジェクト
このレイヤーには、さまざまなテーブルに関連するさまざまなクラスが含まれます。以下のクラスは email テーブル専用です。
メールマッパークラス
public static class EmailMapper
{
public static void IsValid(Func<string, bool> query)
{
var db = new CoinDataContext();
return db.Emails.Count(query) == 0;
}
}
サービス層プロジェクト
このレイヤーは、オブジェクトの一般的な検証を担当しますが、外部 API などの他のレイヤーに移動するためにも使用されます。
EmailService クラス
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;
}
}
Web プロジェクトの属性クラス
public override Boolean IsValid(Object value)
{
return EmailService.IsValid(value.ToString());
}