简体   繁体   English

实体框架DbSet动态查询

[英]Entity Framework DbSet dynamic query

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. 我正在从传入的类型创建DbSet,我需要查询数据库以获取动态字段和值。 Using generics I would use the where function with a lambda expression. 使用泛型时,我会将where函数与lambda表达式一起使用。 Can this be achieved from a standard dbSet created as follows ? 是否可以通过如下创建的标准dbSet来实现?

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. 现在需要查询表以获取数据。

There is a nuget package called 'System.Linq.Dynamic'. 有一个名为“ System.Linq.Dynamic”的nuget包。

http://dynamiclinq.codeplex.com/ http://dynamiclinq.codeplex.com/

This package allows you to form statements against DbSets using strings, like this: 该软件包允许您使用字符串针对DbSet形成语句,如下所示:

myContext.MyDbSet.Where("PropertyName == @0", "aValue"); 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. 在以前的一个项目中,我已经成功地使用了它。

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. 这将是一个完全强类型的解决方案,但是我不确定EF是否支持Count内部的Func<E, P, bool> ,因为目前无法在此进行测试。 But for LINQ to objects this code does work. 但是对于LINQ对象来说,此代码确实有效。

If this does not work you can at least improve it with generics and dynamic LINQ to the following: 如果这不起作用,则至少可以使用泛型和动态LINQ将其改进为以下内容:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM