首页 文章

实体框架DbSet动态查询

提问于
浏览
2

我正在从传入的Type中创建一个DbSet,我需要在数据库中查询动态字段和值 . 使用泛型我会使用带有lambda表达式的where函数 . 这可以通过如下创建的标准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);

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

2 回答

  • 1

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

    http://dynamiclinq.codeplex.com/

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

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

    您可以按照您在问题中的建议使用表达式执行此操作,但此库可以解决所有繁重的问题 .

    我在以前的一个项目中使用过这个并取得了巨大的成功 .

  • 0

    您可以尝试以下内容:

    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对象,这段代码确实有效 .

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

相关问题