我已经为,哦,一两天的编程现在asp.net。这里有一个问题,我甚至不能开始找出自己。

我希望这是从我想要完成的代码很明显,我有,但它是不漂亮。此外,我想用它在任何表格中,任何字段,即检查对一个表和字段我指定一个值的唯一性,所有通入属性构造。

public class UniqueEmailAttribute : ValidationAttribute
{
    public UniqueEmailAttribute()
    {
    }

    public override Boolean IsValid(Object value)
    {
        //not pretty. todo: do away with this.
        var db = new CoinDataContext();
        int c = db.Emails.Count(e => e.Email1 == value.ToString());
        return (Boolean) (c == 0);
    }
}
有帮助吗?

解决方案

刚从布拉德威尔逊 asp.net论坛这。所以满意。没有错误处理!

using System;
using System.ComponentModel.DataAnnotations;
using System.Data.Linq;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

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

        // 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);
        ConstantExpression rhs = Expression.Constant(convertedValue);

        // Expression: "entity"
        ParameterExpression parameter = Expression.Parameter(EntityType, "entity");

        // Expression: "entity.PropertyName"
        MemberExpression property = Expression.MakeMemberAccess(parameter, propertyInfo);

        // 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 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别名以同样的方式BooleanintInt32的别名。无论是可以接受的。我更喜欢小写版本自己。

如亚历克斯在他的答案,这不会是确定的电子邮件地址是否是独一无二的,当它进入数据库的必由之路。只知道它是在检查的时间是唯一的。

最后,和位偏离切线...我已经写入一些LINQ扩展,如下面的类。使用它可以让我重写到db.Emails.None(e => e.Email1 == value.ToString());属性的回归。这使得它点点更具有可读性。

<强>更新 没有确定在数据库中值的唯一没有去的数据库,并针对比较写入的值的行的方式。您还需要创建一个实例数据库。我会做什么,虽然是看这些分隔条件的担忧成不同的区域,例如一个服务层,数据层(MVC的网站项目不同的项目)。您的数据层将完全处理任何与数据库。如果您想我能写的如何你的CoinDataContext从属性本身?

分离出一些例子

解决另一个您的问题,我们在这里移除属性内的查询的需要,但你仍然需要数据库的调用,并且要使用指定的表。

由于这是一个属性不过,我不是100%肯定,如果你能在属性它使用LINQ lambda表达式,所以你的属性在这种方式来保持一概而论。

数据层项目

此层将包含与不同的表不同的类。下面的类专用于电子邮件的表。

电子邮件映射器类

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

我没有把LINQ,但似乎你试图强制唯一客户端。这是不可能的。唯一性约束必须在数据库中执行。如果并发事务提交,办理入住手续已完成刚过一个电子邮件地址,你觉得会怎么样?

即使你检查只是提供一个“对不起,该地址已被使用” -message,还有的还是的另一个事务插入同一地址的可能性。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top