2

I am creating a DbSet from a Type that is passed in and I need to query the database for a dynamic field and value. Using generics I would use the where function with a lambda expression. Can this be achieved from a standard dbSet created as follows ?

DbSet table = dataContext.Set(EntityType);
PropertyInfo propertyInfo = EntityType.GetProperty(PropertyName);

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

// Expression: "entity.PropertyName"
MemberExpression propertyValue = 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(propertyValue, rhs);

// Expression: "entity => entity.PropertyName == value"
LambdaExpression lambda = Expression.Lambda(equal, parameter);

Now need to query the table to get data.

10
  • Not sure if this works with EF. But you could try the dynamic linq lib weblogs.asp.net/scottgu/archive/2008/01/07/… Commented Apr 28, 2014 at 13:37
  • What do you want to achive with this? Maybe there is a better solution... Commented Apr 28, 2014 at 13:46
  • @chrfin - This is a part of validation Attribute, I am passing the attribute name and entity type and need to query Commented Apr 28, 2014 at 14:00
  • Can you show a demo entity and call? Because this sounds like it could be solved differently... Commented Apr 28, 2014 at 14:06
  • Can you give us what the parameters you are getting? I assume a type and is it just the name of the property and an object value or is it an Expression<Func<>> Commented Apr 28, 2014 at 15:06

2 Answers 2

1

There is a nuget package called 'System.Linq.Dynamic'.

http://dynamiclinq.codeplex.com/

This package allows you to form statements against DbSets using strings, like this:

myContext.MyDbSet.Where("PropertyName == @0", "aValue");

It is possible to do this, with Expressions as you suggest in your question, but this library takes out all the heavy lifting.

I've used this with great success in one of my previous projects.

Sign up to request clarification or add additional context in comments.

Comments

0

You can try something like the following:

public class UniqueRecordValidationAttribute : ValidationAttribute
{
    public IValidationAttribute DynamicInstance { get; private set; }

    public UniqueRecordValidationAttribute(Type type, 
        params object[] arguments )
    {
        DynamicInstance = 
            Activator.CreateInstance(type, arguments) as IValidationAttribute;
    }

    public override bool IsValid(object value)
    {
        return DynamicInstance.IsValid(value);
    }
}

public class UniqueRecordValidator<C, E, P> : IValidationAttribute
    where C : DataContext, new() where E : class
{
    Func<E, P, bool> Check { get; set; }

    public UniqueRecordValidator(Func<E, P, bool> check)
    {
        Check = check;
    }

    public bool IsValid(object value)
    {
        DataContext dataContext = new C();
        Table<E> table = dataContext.GetTable<E>();

        return table.Count(i => Check(i as E, (P)value)) == 0;
    }
}

public interface IValidationAttribute
{
    bool IsValid(object value);
}

and

[UniqueRecordValidation(
    typeof(UniqueRecordValidator<AssetTrackingEntities, ATUser_Account, string>), 
    new Func<ATUser_Account, string, bool>((i, p) =>  i.User_Login == p))]
public string User_Name { get; set; }

This would be a completely strongly typed solution, but I am not shure the Func<E, P, bool> inside the Count is supported by EF as I could not test that here at the moment. But for LINQ to objects this code does work.

If this does not work you can at least improve it with generics and dynamic LINQ to the following:

public class UniqueRecordValidator<C, E> : IValidationAttribute
    where C : DataContext, new() where E : class
{
    string PropertyName { get; set; }

    public UniqueRecordValidator(string propertyName)
    {
        PropertyName = propertyName;
    }

    public bool IsValid(object value)
    {
        DataContext dataContext = new C();
        Table<E> table = dataContext.GetTable<E>();

        return table.Count(PropertyName + " = @0", value) == 0;
    }
}

[UniqueRecordValidation(
    typeof(UniqueRecordValidator<AssetTrackingEntities, ATUser_Account>)
    "User_Login")] 
public string User_Login { get; set; } 

2 Comments

Thanks for your suggestions, but are you sure that you can use generics with attributes?? Please check this: stackoverflow.com/questions/9788593/…
Ok, I did not know that. You can use something like here: whathecode.wordpress.com/2013/10/19/generic-attributes-in-c - use the attribute just as a wrapper around the actual generic check.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.