異なるビジネスタイプに対応するため、それぞれ新しいデータベーステーブルを追加する必要があるケースがあります。例えば、ビジネスタイプ「A」に対しては「Table_A」というテーブルがあり、そのフィールドの検証情報を格納するために「Table_VerifyA」という別のテーブルが存在します。
従来のコードでは、以下のような複雑で冗長なロジックが使われていました:
foreach (var pi in typeof(Table_A).GetProperties()) {
if (...) { ... }
else { ... }
foreach (var p2 in typeof(Table_VerifyA).GetProperties()) {
if (...) { ... }
else { ... }
}
}
このコードは非常に読みづらく、保守性も低いです。そこで、属性(Attribute)を使って検証ロジックを簡素化することにしました。
1. 検証インターフェースの定義
まず、すべての検証属性が実装すべきインターフェースを作成します。
/// <summary>
/// フィールド値に基づいて検証規則を初期化します。
/// </summary>
/// <param name="value">フィールドの値</param>
void InitializeRule(object value);
/// <summary>
/// 実際に検証を行います。
/// </summary>
/// <param name="input">検証対象の入力値</param>
/// <param name="errorMessage">エラーメッセージ</param>
/// <returns>検証結果</returns>
bool Validate(object input, out string errorMessage);
2. 具体的な検証属性の実装
以下は最小値チェックを行う属性の例です。
public class MinimumValueValidation : Attribute, IValidation {
private int _minimum;
public void InitializeRule(object value) {
if (value is int intValue && intValue >= 0) {
_minimum = intValue;
} else {
throw new ArgumentException("不正な最小値が指定されました");
}
}
public bool Validate(object input, out string errorMessage) {
errorMessage = string.Empty;
if (input is int inputValue) {
if (inputValue < _minimum) {
errorMessage = $"値は{_minimum}以上である必要があります。";
return false;
}
} else {
errorMessage = "数値以外の値が提供されました。";
return false;
}
return true;
}
}
3. エンティティクラスへの属性適用
次に、エンティティクラスに上記の属性を適用します。
[MinimumValueValidation]
public int SampleField { get; set; }
4. 検証ツールの作成
最後に、属性を使用して自動的に検証を行うユーティリティクラスを作成します。
public class ValidationManager {
private Dictionary _rules = new Dictionary();
public ValidationManager LoadRules<T>(T configuration) where T : class {
var properties = typeof(T).GetProperties();
foreach (var property in properties) {
var attribute = property.GetCustomAttributes(typeof(IValidation), false).FirstOrDefault() as IValidation;
if (attribute != null) {
var value = property.GetValue(configuration);
attribute.InitializeRule(value);
_rules[property.Name] = attribute;
}
}
return this;
}
public bool CheckValidity(object entity, out string failureMessage) {
failureMessage = string.Empty;
var entityProperties = entity.GetType().GetProperties();
foreach (var property in entityProperties) {
if (_rules.TryGetValue(property.Name, out var rule)) {
var value = property.GetValue(entity);
if (!rule.Validate(value, out var error)) {
failureMessage = $"{property.Name}: {error}";
return false;
}
}
}
return true;
}
}
5. 実際の使用例
以下は、実際に検証を行う例です。
var validationManager = new ValidationManager();
validationManager.LoadRules(standards);
if (!validationManager.CheckValidity(targetEntity, out var message)) {
throw new InvalidOperationException(message);
}