实体框架数据库集动态查询

本文关键字:动态 查询 数据库 框架 实体 | 更新日期: 2023-09-27 18:00:27

我正在从传入的Type创建DbSet,我需要在数据库中查询动态字段和值。使用泛型时,我会使用where函数和lambda表达式。这可以通过如下创建的标准数据库集来实现吗?

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

现在需要查询表来获取数据。

实体框架数据库集动态查询

有一个名为"System.Linq.Dynamic"的nuget包。

http://dynamiclinq.codeplex.com/

这个包允许您使用字符串针对DbSet形成语句,如下所示:

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

使用你在问题中建议的表达式可以做到这一点,但这个库省去了所有繁重的工作。

我在以前的一个项目中成功地使用了这个。

您可以尝试以下操作:

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

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

这将是一个完全强类型的解决方案,但我并不担心Count中的Func<E, P, bool>受到EF的支持,因为我目前无法在这里进行测试。但对于LINQ to对象来说,这段代码确实有效。

如果这不起作用,你至少可以用泛型和动态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; }