我如何在C#和DataAnnotation创建一个通用的UniqueValidationAttribute? [英] How can I create a generic UniqueValidationAttribute in C# and DataAnnotation?

查看:182
本文介绍了我如何在C#和DataAnnotation创建一个通用的UniqueValidationAttribute?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图创建使用System.ComponentModel.DataAnnotations.ValidationAttribute一个UniqueAttribute

I'm trying to create a UniqueAttribute using the System.ComponentModel.DataAnnotations.ValidationAttribute

我希望这是通用在我可以通过LINQ的DataContext的,表名,字段和验证,如果输入的值是唯一的或没有。

I want this to be generic as in I could pass the Linq DataContext, the table name, the field and validate if the incoming value is unique or not.

下面是我停留在现在的非编译code片段:

Here is a non-compilable code fragment that I'm stuck at right now:

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());           
        }
    }
}

我要在我的模型如下使用这个:

I should be using this in my model as follows:

[Required]
[StringLength(10)]
[Unique(new DataContext(),"Groups","name")]
public string name { get; set; }

编辑:
注意,根据本<一href=\"http://stackoverflow.com/questions/294216/why-does-c-forbid-generic-attribute-types\">http://stackoverflow.com/questions/294216/why-does-c-forbid-generic-attribute-types
我不能使用泛型类型与属性。

Note that according to this: http://stackoverflow.com/questions/294216/why-does-c-forbid-generic-attribute-types I cannot use a generic type with the attribute.

所以,我在这里新的方法将使用反射/ EX pression树构建移动拉姆达前pression树。

So my new approach here will be using Reflection/Expression trees to construct the Lambda expression tree on the fly.

编辑:
解决了,请检查我的答案!。

Solved, please check my answer!

推荐答案

好吧,有点搜索后,我碰到:的 http://forums.asp.net/t/1512348.aspx
我想通了,尽管它涉及到code公平一点。

Well, after a bit of searching, I came across: http://forums.asp.net/t/1512348.aspx and I figured it out, although it involves a fair bit of code.

用法:

[Required]
[StringLength(10)]
[Unique(typeof(ContactsManagerDataContext),typeof(Group),"name",ErrorMessage="Group already exists")]
public string name { get; set; }

验证器code:

The validator code:

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);
}

我不介意它是丑陋的,因为我将在一个DLL打包和重用,不是执行每桌/场多个UniqueAttribute好得多。

I don't mind it being ugly since I will package it in a DLL and reuse it, much better than implementing multiple UniqueAttribute per table/field.

这篇关于我如何在C#和DataAnnotation创建一个通用的UniqueValidationAttribute?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆