开发者

Validation for unique properties method

开发者 https://www.devze.com 2023-02-21 21:10 出处:网络
I was trying to write a method to be called from a CustomValidator to determine whether a string property was unique or not. I was trying to make it generic so that I can reuse the code for many diffe

I was trying to write a method to be called from a CustomValidator to determine whether a string property was unique or not. I was trying to make it generic so that I can reuse the code for many different string properties. I'm using reflection. Does this seem like a way too complicated way of doing this? Does there happen to be a better way of doing this but still making it generic?

public virtual bool IsPropertyUnique(T entity, string newValue, str开发者_如何学Pythoning propertyName)
        {
            var values =
                Context.GetTable<T>.Where(e => string.Equals(e.GetType().GetProperty(propertyName).GetValue(e, null), newValue)).ToList();

            return values.Count == 0;
        }


One possible improvement:

public virtual bool IsPropertyUnique(T entity, string newValue, string propertyName)
{
    var propertyInfo = typeof(t).GetProperty(propertyName);
    return !FindAll()
           .Any(e => string.Equals(propertyInfo.GetValue(e, null), newValue));
}


Since this is LINQ to SQL you need to provide something that it can understand and parse into SQL. At the moment it's going to see a bunch of crazy reflection and start to cry.

You could change the form of your method call to

public Exists(Expression<Func<T, bool>> filter)
{
     return Context.GetTable<T>.Any(filter);
}

// Usage
string valueToCheck = "Boo!";
bool exists = Exists(t => t.Bar == valueToCheck);
if (exists)
{
    return "BAD USER - PICK SOMETHING UNIQUE";
}

and that'd work just fine.

If you wanted to preserve your method signature you have to get down and dirty with expression trees. Basically you want to create the following expression so LINQ to SQL can go "oh yeah that's a where clause on the column that corresponds to the property 'Bar'"

t => t.Bar == valueToCheck

To recreate you'd need to do the following

private static Expression<Func<T, bool>> GetPredicate(string property, string value)
{
    // First you need a parameter of the correct type
    ParameterExpression parameter = Expression.Parameter(typeof (T), "t");

    // Then use that parameter to access the appropriate property
    MemberExpression propertyToAccess = Expression.Property(parameter, typeof (T), property);

    // Introduce the constant value to check
    ConstantExpression valueToCompare = Expression.Constant(value);

    // Make sure they're equal
    Expression comparison = Expression.Equal(propertyToAccess, valueToCompare);

    // and create the expression based on the method body and the parameter...
    return (Expression<Func<T, bool>>)Expression.Lambda(comparison, parameter);
}

public IsPropertyUnique(T entity, string property, string value)
{
    return !Context.GetTable<T>.Any(GetPredicate(property, value));
}

Also using Any instead of Where here can be slightly more performant as it doesn't have to load the matching records out of the DB (it'll just do a IF EXISTS instead).

0

精彩评论

暂无评论...
验证码 换一张
取 消