ValidationAttribute Redux

Link to: Create a ValidationAttribute to provide unique column values.

Ok ... Let's try to rephrase the question:

from here I ripped this code:

    static TEntity Get<TEntity, TKey>(this DataContext ctx, TKey key) where TEntity : class
    {
        var table = ctx.GetTable<TEntity>();
        var pkProp = (from member in ctx.Mapping.GetMetaType(typeof(TEntity)).DataMembers
                      where member.IsPrimaryKey
                      select member.Member).Single();
        ParameterExpression param = Expression.Parameter(typeof(TEntity), "x");
        MemberExpression memberExp;
        switch (pkProp.MemberType)
        {
            case MemberTypes.Field: memberExp = Expression.Field(param, (FieldInfo)pkProp); break;
            case MemberTypes.Property: memberExp = Expression.Property(param, (PropertyInfo)pkProp); break;
            default: throw new NotSupportedException("Invalid primary key member: " + pkProp.Name);
        }
        Expression body = Expression.Equal(
        memberExp, Expression.Constant(key, typeof(TKey)));
        var predicate = Expression.Lambda<Func<TEntity, bool>>(body, param);
        return table.Single(predicate);
    }

      

This is a DataContext extension method that has the things I need. However, this requires generic parms, which I don't have - attributes don't allow generic subframes, so ....

I hacked the code up to this point:

    public override bool IsValid(object value)
        SomeDataContext context = SomeDataContext.GetNewDataContext();
        var table = context.GetTable(_EntityType);
        var codeProp = (from member in context.Mapping.GetMetaType(_EntityType).DataMembers
                        where member.Name == _PropertyName
                        select member.Member).Single();
        ParameterExpression param = Expression.Parameter(_EntityType, "x");
        MemberExpression memberExp = Expression.Property(param, (PropertyInfo)codeProp); 
        Expression body = Expression.Equal(memberExp, Expression.Constant(value, typeof(char)));
        Type lambdaType = typeof(Func<,>).MakeGenericType(_EntityType, typeof(bool)); 
        var predicate = Expression.Lambda(lambdaType, body, param); 
        object code = table.FirstOrDefault(predicate);
        if (code != null)
        {
            return false;
        }
        return true;
    }

      

This line is bad:

        object code = table.FirstOrDefault(predicate);

      

as I said here the answers to which do not help.

  • var enumerator = ((IEnumerable)table).GetEnumerator();object code = enumerator.MoveNext() ? enumerator.Value : null;


    not helpful in my attempt to build an expression tree.
  • IEnumerable<object> tableGeneric = ((IEnumerable)table).OfType<object>();


    has problems when i try:
    object code = tableGeneric.FirstOrDefault(predicate);


So, I'm pretty stuck. Any ideas out there?

Thanks.

0


a source to share


1 answer


The end result you might be looking for is that, as far as I can tell, you really need a method like:

public bool IsValid<TEntity>()
{
    // validation logic goes here
}

      

So that you can do the check (s) you need, but you need to implement it in a method that is only available to it:

public bool IsValid(Type entityType)
{
    // ???
}

      



If so, then you implement the first block of code with the necessary logic, and you implement the second method as:

public bool IsValidWrapper(Type entityType)
{
    // You may want to be stricter than this, but the essence is to
    // get a handle to the generic method first...
    MethodInfo genMethod = GetType().GetMethod("IsValid");

    // Bind it to the type you want to operate on...
    MethodInfo method = genMethod.MakeGenericMethod(entityType);

    // And invoke it...
    return (bool) method.Invoke(this, null);
}

      

It won't win beauty pageants or performance crowns, but you will get what you need. Note that if performance is an issue, you can keep the lookup from Type

up to the signed delegate bool delegate()

so that you don't have to use slow reflection for a given type more than once to perform type binding.

0


a source







All Articles