数据库接口的动态可查询参数

本文关键字:查询 参数 动态 接口 数据库 | 更新日期: 2023-09-27 17:54:38

我会保持问题简短,因为我怀疑答案可能是简短的"不"。我想能够通过查询到一个实体框架功能,使动态运行时查询通过ui到数据库?我想象这就像传递一个IQueryable到一个方法,但确切地说,我将如何去做这件事,我现在有点不确定。我想错了吗?也许是在业务层进行查询,而不是半直接对数据库进行查询?

数据库接口的动态可查询参数

根据评论,我提供了两个选项。

  1. 基于给用户的一组选项。使用TreeExpression动态地构建表达式,就像上面的例子(这个例子确实太简单了,但是你可以有一个想法)。

    ParameterExpression numParam = Expression.Parameter(typeof(int), "num");
    ConstantExpression five = Expression.Constant(5, typeof(int));
    BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);
    Expression<Func<int, bool>> lambda1 = Expression.Lambda<Func<int, bool>>(numLessThanFive, new ParameterExpression[] { numParam });
    

这个链接会给你更多关于这个主题的信息:https://msdn.microsoft.com/en-us/library/bb882637.aspx

  • 为了让用户键入一些表达式并将其转换为查询,搜索Antlr http://www.antlr.org/或类似的工具,允许您想要实现的表达式语法并使用1º解决方案来构建表达式。
  • 我的示例代码如下:您需要安装以下包…

    install-package entityframework
    install-package newtonsoft.json
    

    请注意,通过插入有效的VB,这段代码很容易被注入。

    我将代码编译成30742268.exe,您可以看到它被添加为IContext接口的参考,等等。

    using System;
    using System.Linq;
    using System.Text;
    using Microsoft.VisualBasic;
    using System.CodeDom.Compiler;
    using Model;
    using System.Collections.Generic;
    using System.Data.Entity;
    using Newtonsoft.Json;
    namespace _30742268 {
        class Program {
            const String queryWrapperCode = @"
                Imports System.Linq
                Imports System.Data.Entity
                Imports Model
                Public Class DynamicQuery
                    Implements IDynamicQuery
                    Public Function Run(data As IContext) As IQueryable Implements IDynamicQuery.Run
                        Return {0}
                    End Function
                End Class
            ";
            static void Main(String[] args) {
                using (var provider = new VBCodeProvider()) {
                    var parameters = new CompilerParameters();
                    parameters.ReferencedAssemblies.Add("System.Core.dll");
                    parameters.ReferencedAssemblies.Add("EntityFramework.dll");
                    parameters.ReferencedAssemblies.Add("30742268.exe");
                    parameters.GenerateInMemory = true;
                    Console.WriteLine("Enter LINQ queries, 'demo' for an example, 'exit' to stop:");
                    for (;;) {
                        try {
                            var dynamicQueryString = Console.ReadLine();
                            if (dynamicQueryString == "exit")
                                return;
                            if (dynamicQueryString == "demo")
                                Console.WriteLine(dynamicQueryString = "from person in data.People where person.Name.Length = 4");
                            var results = provider.CompileAssemblyFromSource(parameters, String.Format(queryWrapperCode, dynamicQueryString));
                            if (results.Errors.HasErrors) {
                                var sb = new StringBuilder();
                                foreach (CompilerError error in results.Errors) {
                                    sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
                                }
                                throw new InvalidOperationException(sb.ToString());
                            }
                            var assembly = results.CompiledAssembly;
                            var assemblyType = assembly.GetTypes().Single(x => typeof (IDynamicQuery).IsAssignableFrom(x));
                            var constructorInfo = assemblyType.GetConstructor(new Type[] {});
                            var dynamicQuery = (IDynamicQuery) constructorInfo.Invoke(null);
                            using (var context = new Context()) {
                                dynamic result = dynamicQuery.Run(context);
                                foreach (var person in result)
                                    Console.WriteLine(person);
                            }
                        }
                        catch (Exception exception) {
                            Console.WriteLine(exception);
                        }
                    }
                }
            }
        }
    }
    namespace Model {
        public interface IDynamicQuery {
            IQueryable Run(IContext context);
        }
        public abstract class Entity {
            public override String ToString() {
                return JsonConvert.SerializeObject(this, Formatting.Indented, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
            }
        }
        public class Person : Entity {
            public Int64 Id { get; protected set; }
            public String Name { get; set; }
            public virtual Home Home { get; set; }
        }
        public class Home : Entity {
            public Int64 Id { get; protected set; }
            public String Address { get; set; }
            public virtual ICollection<Person> Inhabitants { get; set; } 
        }
        public interface IContext {
            IQueryable<Person> People { get; set; }
            IQueryable<Home> Homes { get; set; }
        }
        public class Context : DbContext, IContext {
            public virtual DbSet<Person> People { get; set; }
            public virtual DbSet<Home> Homes { get; set; }
            IQueryable<Person> IContext.People {
                get { return People; }
                set { People = (DbSet<Person>)value; }
            }
            IQueryable<Home> IContext.Homes {
                get { return Homes; }
                set { Homes = (DbSet<Home>)value; }
            }
            public Context() {
                Configuration.ProxyCreationEnabled = false;
                Database.SetInitializer(new ContextInitializer());
            }
        }
        class ContextInitializer : DropCreateDatabaseAlways<Context> {
            protected override void Seed(Context context) {
                var fakeSt = new Home {Address = "123 Fake St."};
                var alabamaRd = new Home {Address = "1337 Alabama Rd."};
                var hitchhikersLn = new Home {Address = "42 Hitchhiker's Ln."};
                foreach (var home in new[] {fakeSt, alabamaRd, hitchhikersLn})
                    context.Homes.Add(home);
                context.People.Add(new Person { Home = fakeSt       , Name = "Nick" });
                context.People.Add(new Person { Home = fakeSt       , Name = "Paul" });
                context.People.Add(new Person { Home = fakeSt       , Name = "John" });
                context.People.Add(new Person { Home = fakeSt       , Name = "Henry" });
                context.People.Add(new Person { Home = alabamaRd    , Name = "Douglas" });
                context.People.Add(new Person { Home = alabamaRd    , Name = "Peter" });
                context.People.Add(new Person { Home = alabamaRd    , Name = "Joshua" });
                context.People.Add(new Person { Home = hitchhikersLn, Name = "Anne" });
                context.People.Add(new Person { Home = hitchhikersLn, Name = "Boris" });
                context.People.Add(new Person { Home = hitchhikersLn, Name = "Nicholes" });
                context.People.Add(new Person { Home = hitchhikersLn, Name = "Betty" });
                context.SaveChanges();
            }
        }
    }