如何在C#和DataAnnotation中创建通用UniqueValidationAttribute?
我正在尝试使用如何在C#和DataAnnotation中创建通用UniqueValidationAttribute?,c#,linq-to-sql,validation,asp.net-mvc-2,data-annotations,C#,Linq To Sql,Validation,Asp.net Mvc 2,Data Annotations,我正在尝试使用System.ComponentModel.DataAnnotations.ValidationAttribute 我希望这是通用的,因为我可以传递linqdatacontext、表名、字段,并验证传入值是否唯一 下面是一个我目前一直无法编译的代码片段: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel.D
System.ComponentModel.DataAnnotations.ValidationAttribute
我希望这是通用的,因为我可以传递linqdatacontext、表名、字段,并验证传入值是否唯一
下面是一个我目前一直无法编译的代码片段:
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());
}
}
}
我应该在我的模型中使用它,如下所示:
[Required]
[StringLength(10)]
[Unique(new DataContext(),"Groups","name")]
public string name { get; set; }
编辑:
请注意,根据这一点:
我无法将泛型类型与属性一起使用
因此,我的新方法是使用反射/表达式树动态构造Lambda表达式树。我已经看到的一个问题是,不能将类型实例化为属性的参数 属性要求所有参数都是编译时常量。因此,用法:
[Unique(new DataContext(),"Groups","name")]
不会编译。您可能可以省略
new DataContext()
——但是我怀疑您的验证逻辑不会包含有关要查询的实体类型的信息。正如@LBushkin提到的,属性需要编译时常量
我会把你的班级从:
public class UniqueAttribute : ValidationAttribute
致:
并将其用作:
[Required]
[StringLength(10)]
[Unique<DataContext>("Groups","name")]
public string name { get; set; }
[Required]
[StringLength(10)]
[Unique(typeof(DataContext), "Groups","name")]
public string name { get; set; }
这一次:)嗯,经过一番搜索,我发现:
我找到了答案,虽然它需要相当多的代码
用法:
[Required]
[StringLength(10)]
[Unique(typeof(ContactsManagerDataContext),typeof(Group),"name",ErrorMessage="Group already exists")]
public string name { get; set; }
验证程序代码:
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);
}
public类UniqueAttribute:ValidationAttribute
{
公共类型DataContextType{get;private set;}
公共类型EntityType{get;private set;}
公共字符串PropertyName{get;private set;}
公共UniqueAttribute(类型dataContextType、类型entityType、字符串propertyName)
{
DataContextType=DataContextType;
EntityType=EntityType;
PropertyName=PropertyName;
}
公共覆盖布尔值有效(对象值)
{
字符串str=(字符串)值;
if(String.IsNullOrWhiteSpace(str))
返回true;
//清理字符串
str=str.Trim();
//构建数据上下文
ConstructorInfo构造函数=DataContextType.GetConstructor(新类型[0]);
DataContext=(DataContext)构造函数.Invoke(新对象[0]);
//收拾桌子
ITable table=dataContext.GetTable(EntityType);
//取得财产
PropertyInfo PropertyInfo=EntityType.GetProperty(PropertyName);
//表述:“实体”
ParameterExpression参数=Expression.parameter(EntityType,“entity”);
//表达式:“entity.PropertyName”
MemberExpression属性=Expression.MakeMemberAccess(参数,propertyInfo);
//表达:“价值”
object convertedValue=Convert.ChangeType(值,propertyInfo.PropertyType);
ConstantExpression rhs=表达式常数(convertedValue);
//表达式:“entity.PropertyName==value”
BinaryExpression equal=表达式.equal(属性,rhs);
//表达式:“entity=>entity.PropertyName==value”
LambdaExpression lambda=表达式.lambda(等于,参数);
//使用正确的TSource(我们的实体类型)实例化count方法
MethodInfo countMethod=QueryableCountMethod.MakeGenericMethod(EntityType);
//执行Count()并说“如果没有匹配项,则为有效”
int count=(int)countMethod.Invoke(null,新对象[]{table,lambda});
返回计数==0;
}
//获取可查询的.Count(IQueryable,表达式)
私有静态MethodInfo QueryableCountMethod=typeof(Queryable).GetMethods().First(m=>m.Name==“Count”&&m.GetParameters().Length==2);
}
我不介意它很难看,因为我会将它打包到一个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);
}
public类UniqueAttribute:ValidationAttribute
{
公共UniqueAttribute(类型dataContextType、类型entityType、字符串propertyName)
{
DataContextType=DataContextType;
EntityType=EntityType;
PropertyName=PropertyName;
}
公共类型DataContextType{get;private set;}
公共类型EntityType{get;private set;}
公共字符串PropertyName{get;private set;}
公共覆盖布尔值有效(对象值)
{
//构建数据上下文
//ConstructorInfo构造函数=DataContextType.GetConstructor(新类型[0]);
//DataContext=(DataContext)构造函数.Invoke(新对象[0]);
var repository=DependencyResolver.Current.GetService(DataContextType);
var data=repository.GetType().InvokeMember(“GetAll”,BindingFlags.Instance | BindingFlags.InvokeMethod | BindingFlags.Public,null,repository,null);
//收拾桌子
//ITable table=dataContext.GetTable(EntityType);
//取得财产
PropertyInfo PropertyInfo=EntityType.GetProperty(PropertyName);
//我们的最终目标是:
//“entity=>entity.PropertyName==值”
//表达:“价值”
object convertedValue=Convert.ChangeType(值,propertyInfo.PropertyType);
var rhs=表达式常数(convertedValue);
//表述:“实体”
var参数=Expression.parameter(EntityType,“实体”);
//表达式:“entity.PropertyName”
var property=Expression.MakeMemberAccess(参数,propertyInfo);
//表达式:“entity.PropertyName==value”
var equal=表达式.equal(属性,rhs);
//表达式:“entity=>entity.PropertyName==value”
var lambda=Expression.lambda(等于,参数).Compile();
//使用正确的TSource(我们的实体类型)实例化count方法
MethodInfo countMethod=QueryableCountMethod.MakeGenericMethod(EntityType);
//执行Count()并说“如果没有,则为有效”
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);
}
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);
}