Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/316.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/vim/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用Linq而不是SQL字符串构造查询_C#_.net_Sql_Linq - Fatal编程技术网

C# 使用Linq而不是SQL字符串构造查询

C# 使用Linq而不是SQL字符串构造查询,c#,.net,sql,linq,C#,.net,Sql,Linq,我有一个2.0服务器控件,它使用动态查询,大致如下: string sql = "Select " + columnvariable + " FROM " + tablenamevariable 因此,很明显,您可以从DB中的任何有效表中为它指定任何有效的列名,并且它会将列中的值返回到DataReader中(在本例中) 我正试图减少代码库中显式逐段SQL的数量,并且更愿意在LINQ中这样做。有没有一个简单的方法可以做到这一点?这样做明智吗?我认为,在本例中,生成的逐段SQL非常通用,因此在本例

我有一个2.0服务器控件,它使用动态查询,大致如下:

string sql = "Select " + columnvariable + " FROM " + tablenamevariable
因此,很明显,您可以从DB中的任何有效表中为它指定任何有效的列名,并且它会将列中的值返回到DataReader中(在本例中)

我正试图减少代码库中显式逐段SQL的数量,并且更愿意在LINQ中这样做。有没有一个简单的方法可以做到这一点?这样做明智吗?我认为,在本例中,生成的逐段SQL非常通用,因此在本例中不会真正造成安全问题

即便如此,它似乎还是有一些相当基本的功能,所以我很好奇。我已经在我的项目中包含了System.Linq.Dynamic,但这似乎阻止了程序员动态选择他们想要的动态列的表

我的意思不是讨论。我想要一个类似“是的,这是可能的,很简单,这里是如何…”或“是的,但只有当您构建这套精心设计的处理程序类并基本上重写LINQ的部分时,这里是如何…”的答案


然而,我很想知道人们是否认为在林克做这种事情可以最好地描述为a)一个愉快的好主意或b)疯狂的谈话。

瑞克·斯特拉尔博客中的这篇文章似乎在谈论这个话题:

在没有任何更清楚的东西的情况下,我想我应该基于此做出选择

任何其他潜在的回答者都应该考虑他们的潜在答案是否比上述链接更清晰。如果没有,那么你参与进来可能是浪费时间

编辑:尽管这在上述文章中链接到:


完全澄清了我的问题,事实上,这是另一篇文章的前传。有趣的东西。

这里有一个来自优秀的老斯科特·顾(三次)的例子:

您的查询:


string sql=“从“+tablenamevariable”中选择“+columnvariable+”

可以用LINQ“翻译”如下:

public IQueryable<Customer> GetCustomers<T>(Expression<Func<Customer, T>> column)
{
    return db.Customers.Select(column);
}
var customerNames = GetColumn<string>("Customers", "CustomerName");

var sql=(从tablenamevariable选择columnvariable).ToList();

现在,“sql”变量包含存储在“tablenamevariable”中的“columnvariable”列表


你可以用LINQ使事情变得简单。

你从错误的角度来做这件事。你认为你想要这个:

void DoStuff(tablenamevariable, columnvariable)
{
    string sql = "Select " + columnvariable + " FROM " + tablenamevariable 
    // read data 
}


DoStuff("MyTable", "MyColumn");
为什么会有这样的界面?这有什么错

void DoStuff<T>(IQueryable<T> query)
{
      // read data
}


DoStuff(from t in MyTable select t.MyColumn);

不幸的是,您的问题没有明确说明
columnvariable
的确切来源,但是如果允许我做出以下假设,那么我想我可以为您提供一个几乎微不足道的解决方案:

  • 假设1:
    columnvariable
    是一个通过方法调用传递的值,但最终它是一个常量。即,它不是用户提供的字符串,也不是从文件中读取的字符串,等等

  • 假设2:您可以访问为
    列变量
    传入这些常量的所有代码

如果这些假设成立,那么我的建议是更改包含以下内容的方法:

string sql = "Select " + columnvariable + " FROM " + tablenamevariable
更像这样:

public IQueryable<Customer> GetCustomers<T>(Expression<Func<Customer, T>> column)
{
    return db.Customers.Select(column);
}
var customerNames = GetColumn<string>("Customers", "CustomerName");
你会说

// Properly type-safe and compile-time checked
var myCustomers = GetCustomers(c => c.CustomerName);

既然你在寻找一个直截了当的答案。。。不,这在LINQ是不可能的


LINQ本质上是强类型的,而您正在寻找完全动态的东西。如果您的表和列是运行时变量(即字符串),那么您的SQL将需要是字符串。。。或者您需要使用ORM(NHibernate、L2S、EF等)来访问数据。

如果您需要完全动态的数据,即表名和列名可以有任何字符串,那么我怀疑您唯一的选择是手动构建表达式树。类似于

public IQueryable<TResult> GetColumn<TResult>(string tableName, string columnName)
{
    // Get the table, e.g. for "Customers" get db.Customers
    var table = db.GetType().GetField(tableName).GetValue(db);

    // Find the specific type parameter (the T in IQueryable<T>)
    var iqueryableT = table.GetType().FindInterfaces((ty, obj) => ty.IsGenericType && ty.GetGenericTypeDefinition() == typeof(IQueryable<>), null).FirstOrDefault();
    var type = iqueryableT.GetGenericArguments()[0];

    // Construct a query that retrieves the relevant column
    var param = Expression.Parameter(type);
    var prop = Expression.Property(param, columnName);
    var expression = Expression.Lambda(prop, param);

    // Call Queryable.Select() with the appropriate parameters
    // Notice there are two Select methods, need to get the right one...
    return (IQueryable<TResult>) typeof(Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public)
        .Where(meth => meth.Name == "Select")
        .Select(meth => meth.MakeGenericMethod(type, typeof(TResult)))
        .Where(meth => meth.GetParameters()[1].ParameterType == typeof(Expression<>).MakeGenericType(typeof(Func<,>).MakeGenericType(type, typeof(TResult))))
        .First()
        .Invoke(null, new object[] { table, expression });
}
publicIQueryable GetColumn(字符串tableName,字符串columnName)
{
//获取表格,例如“客户”获取数据库客户
var table=db.GetType().GetField(tableName).GetValue(db);
//查找特定类型参数(IQueryable中的T)
var iqueryableT=table.GetType().FindInterfaces((ty,obj)=>ty.IsGenericType&&ty.GetGenericTypeDefinition()==typeof(IQueryable),null);
var type=iqueryableT.GetGenericArguments()[0];
//构造一个检索相关列的查询
var param=表达式参数(类型);
var prop=Expression.Property(param,columnName);
变量表达式=表达式.Lambda(prop,param);
//使用适当的参数调用Queryable.Select()
//请注意,有两种选择方法,需要获得正确的方法。。。
return(IQueryable)typeof(Queryable).GetMethods(BindingFlags.Static | BindingFlags.Public)
.Where(meth=>meth.Name==“选择”)
.Select(meth=>meth.MakeGenericMethod(type,typeof(TResult)))
.Where(meth=>meth.GetParameters()[1]。ParameterType==typeof(表达式)。MakeGenericType(typeof(Func)。MakeGenericType(type,typeof(TResult)))
.First()
.Invoke(null,新对象[]{table,expression});
}
然后你可以这样称呼它:

public IQueryable<Customer> GetCustomers<T>(Expression<Func<Customer, T>> column)
{
    return db.Customers.Select(column);
}
var customerNames = GetColumn<string>("Customers", "CustomerName");
var CustomerName=GetColumn(“客户”、“客户名称”);

当然,您仍然需要知道列的类型,因为您希望它返回一个正确的强类型queryable。或者,您可以添加一个
表达式;然后,您不需要每次都指定
字符串,但当然,您的列数据将被转换为字符串,可能会丢失。

LINQ to SQL:这与我的想法不完全一样。。。也许举个例子就可以了。如果可能的话,最好把它去掉。您是否考虑过,如果通过恶意用户输入,
tablenamerable
变成
“myTable;DROP TABLE ReallyImportantable;”会发生什么情况。仔细阅读SQL注入。@Winston:这是一个很好的观点。风险