sab*_*our 4 c# validation linq-to-sql data-annotations asp.net-mvc-2
我正在尝试创建一个UniqueAttribute使用System.ComponentModel.DataAnnotations.ValidationAttribute
我希望这是通用的,因为我可以传递Linq DataContext,表名,字段并验证传入值是否唯一.
这是一个不可编译的代码片段,我现在卡在这里:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
using System.Data.Linq;
using System.ComponentModel;
namespace LinkDev.Innovation.Miscellaneous.Validation.Attributes
{
public class UniqueAttribute : ValidationAttribute
{
public string Field { get; set; }
public override bool IsValid(object value)
{
string str = (string)value;
if (String.IsNullOrEmpty(str))
return true;
// this is where I'm stuck
return (!Table.Where(entity => entity.Field.Equals(str)).Any());
}
}
}
Run Code Online (Sandbox Code Playgroud)
我应该在我的模型中使用它如下:
[Required]
[StringLength(10)]
[Unique(new DataContext(),"Groups","name")]
public string name { get; set; }
Run Code Online (Sandbox Code Playgroud)
编辑:请注意,根据这个:为什么C#禁止通用属性类型? 我不能使用属性的泛型类型.
所以我的新方法是使用Reflection/Expression树来动态构建Lambda表达式树.
好吧,经过一些搜索后,我偶然发现:http://forums.asp.net/t/1512348.aspx 我想出来了,虽然它涉及到相当多的代码.
用法:
[Required]
[StringLength(10)]
[Unique(typeof(ContactsManagerDataContext),typeof(Group),"name",ErrorMessage="Group already exists")]
public string name { get; set; }
Run Code Online (Sandbox Code Playgroud)
验证码:
public class UniqueAttribute : ValidationAttribute
{
public Type DataContextType { get; private set; }
public Type EntityType { get; private set; }
public string PropertyName { get; private set; }
public UniqueAttribute(Type dataContextType, Type entityType, string propertyName)
{
DataContextType = dataContextType;
EntityType = entityType;
PropertyName = propertyName;
}
public override bool IsValid(object value)
{
string str = (string) value;
if (String.IsNullOrWhiteSpace(str))
return true;
// Cleanup the string
str = str.Trim();
// Construct the data context
ConstructorInfo constructor = DataContextType.GetConstructor(new Type[0]);
DataContext dataContext = (DataContext)constructor.Invoke(new object[0]);
// Get the table
ITable table = dataContext.GetTable(EntityType);
// Get the property
PropertyInfo propertyInfo = EntityType.GetProperty(PropertyName);
// Expression: "entity"
ParameterExpression parameter = Expression.Parameter(EntityType, "entity");
// Expression: "entity.PropertyName"
MemberExpression property = Expression.MakeMemberAccess(parameter, propertyInfo);
// Expression: "value"
object convertedValue = Convert.ChangeType(value, propertyInfo.PropertyType);
ConstantExpression rhs = Expression.Constant(convertedValue);
// Expression: "entity.PropertyName == value"
BinaryExpression equal = Expression.Equal(property, rhs);
// Expression: "entity => entity.PropertyName == value"
LambdaExpression lambda = Expression.Lambda(equal, parameter);
// Instantiate the count method with the right TSource (our entity type)
MethodInfo countMethod = QueryableCountMethod.MakeGenericMethod(EntityType);
// Execute Count() and say "you're valid if you have none matching"
int count = (int)countMethod.Invoke(null, new object[] { table, lambda });
return count == 0;
}
// Gets Queryable.Count<TSource>(IQueryable<TSource>, Expression<Func<TSource, bool>>)
private static MethodInfo QueryableCountMethod = typeof(Queryable).GetMethods().First(m => m.Name == "Count" && m.GetParameters().Length == 2);
}
Run Code Online (Sandbox Code Playgroud)
我不介意它是丑陋的,因为我将它打包在DLL中并重用它,比每个表/字段实现多个UniqueAttribute要好得多.
我编辑了这个..它与 DI 完美配合..:D
public class UniqueAttribute : ValidationAttribute
{
public UniqueAttribute(Type dataContextType, Type entityType, string propertyName)
{
DataContextType = dataContextType;
EntityType = entityType;
PropertyName = propertyName;
}
public Type DataContextType { get; private set; }
public Type EntityType { get; private set; }
public string PropertyName { get; private set; }
public override bool IsValid(object value)
{
// Construct the data context
//ConstructorInfo constructor = DataContextType.GetConstructor(new Type[0]);
//DataContext dataContext = (DataContext)constructor.Invoke(new object[0]);
var repository = DependencyResolver.Current.GetService(DataContextType);
var data = repository.GetType().InvokeMember("GetAll", BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public, null, repository, null);
// Get the table
//ITable table = dataContext.GetTable(EntityType);
// Get the property
PropertyInfo propertyInfo = EntityType.GetProperty(PropertyName);
// Our ultimate goal is an expression of:
// "entity => entity.PropertyName == value"
// Expression: "value"
object convertedValue = Convert.ChangeType(value, propertyInfo.PropertyType);
var rhs = Expression.Constant(convertedValue);
// Expression: "entity"
var parameter = Expression.Parameter(EntityType, "entity");
// Expression: "entity.PropertyName"
var property = Expression.MakeMemberAccess(parameter, propertyInfo);
// Expression: "entity.PropertyName == value"
var equal = Expression.Equal(property, rhs);
// Expression: "entity => entity.PropertyName == value"
var lambda = Expression.Lambda(equal, parameter).Compile();
// Instantiate the count method with the right TSource (our entity type)
MethodInfo countMethod = QueryableCountMethod.MakeGenericMethod(EntityType);
// Execute Count() and say "you're valid if you have none matching"
int count = (int)countMethod.Invoke(null, new object[] { data, lambda });
return count == 0;
}
// Gets Queryable.Count<TSource>(IQueryable<TSource>, Expression<Func<TSource, bool>>)
//private static MethodInfo QueryableCountMethod = typeof(Enumerable).GetMethods().First(m => m.Name == "Count" && m.GetParameters().Length == 2);
private static MethodInfo QueryableCountMethod = typeof(System.Linq.Enumerable).GetMethods().Single(
method => method.Name == "Count" && method.IsStatic && method.GetParameters().Length == 2);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8047 次 |
| 最近记录: |