【问题标题】:How can I add parameter to Filter stored procedure XML in C#?如何在 C# 中将参数添加到过滤存储过程 XML?
【发布时间】:2016-10-31 18:18:42
【问题描述】:

我有一个发送 XML 的存储过程:

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

ALTER PROCEDURE [dbo].[ChartEnergyKPIS]
    @columns varchar(max),
    @groupBy varchar(max),
    @filters varchar(max)
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @query varchar(max)
    SET @query = 'declare @xml XML

    SET @xml = (SELECT '+ @columns + ' 
                FROM [dbo].[KPIS] k (NOLOCK)
                INNER JOIN [dbo].[KPISEnergy]  ke (NOLOCK) ON k.Id = ke.IdKPI
                INNER JOIN [dbo].[Meter] m (NOLOCK) ON ke.IdMeter = m.Id
                ' + @filters + ' ' +
                @groupBy + ' FOR XML RAW) SELECT @xml';

    PRINT @query
    EXEC(@query)
END

我想做的是通过k.BranchOfficeId 过滤这个 XML,在 C# 类中我将查询称为:

public static string GetChartEnergy(string initDate, string endDate, string type)
{
    string result = string.Empty;
    var structure = new List<QueryStructure>();

    try
    {
        structure.Add(initDate.CreateQueryStructure(endDate, true, null, "convert(datetime,'15/' + CONVERT(varchar(10), k.Month) + '/' +  CONVERT(varchar(10), k.Year), 103)", null, false));
        structure.Add(type.CreateQueryStructure(string.Empty, false, "CASE WHEN m.Type = 1 THEN 'Agua' ELSE CASE WHEN m.Type = 2 THEN 'Luz' ELSE 'Gas' END END AS Type", " m.type", "m.Type", false));

        //agrega una columna para sacar el total de registros por filtro
        structure.Add(new QueryStructure
                {
                    ColumnSelect = "SUM(ke.Month) AS Total",
                    Operator = Operator.Nothing,
                    ColumnWhere = string.Empty
                });

        result = Chars.GetChartInfo(structure, "ChartEnergyKPIS");
    }
    catch (Exception)
    {
        throw;
    }

    return result;
}

所以我的尝试很简单,将过滤器添加到创建查询中,并与我在方法中调用的 currentUser 进行比较:

public static string GetChartEnergy(string initDate, string endDate, string type, int currentUser)
{
    string result = string.Empty;
    var structure = new List<QueryStructure>();

    try
    {
        structure.Add(initDate.CreateQueryStructure(endDate, true, null, "convert(datetime,'15/' + CONVERT(varchar(10), k.Month) + '/' +  CONVERT(varchar(10), k.Year), 103,k.BranchOfficeId = currentUser)", null, false));

最后在一个类中,我执行一个存储过程并根据应用的过滤器获取 Json:

public static string GetChartInfo(List<QueryStructure> queryStructure, string procedureName)
{
    string result = string.Empty;
    string xml = string.Empty;

    try
    {
        var queryWhere = queryStructure.GetWhere();
        var columnsQuery = queryStructure.GetSelectGroupBy(true);
        var groupByQuery = queryStructure.GetSelectGroupBy(false);

        using (var oContext = new EF.SSMA())
        {
             SqlParameter param1 = new SqlParameter("@columns", columnsQuery);
             SqlParameter param2 = new SqlParameter("@groupBy", groupByQuery);
             SqlParameter param3 = new SqlParameter("@filters", queryWhere);

             xml = oContext.Database.SqlQuery<string>(string.Format("dbo.{0}  @columns, @groupBy, @filters", procedureName), param1, param2, param3).First();
         }

         if (!string.IsNullOrEmpty(xml))
         {
             XmlDocument doc = new XmlDocument();
             doc.LoadXml(string.Format("<root>{0}</root>", xml));
             doc.LoadXml("<root>" + xml + "</root>");

             result = Newtonsoft.Json.JsonConvert.SerializeXmlNode(doc);
             result = result.Replace("{\"root\":{\"row\":", "");
             result = result.Replace("}}", "");
             result = result.Replace("\"@", "\"");

             if (result.Substring(0, 1) == "{")
             {
                 result = string.Format("[{0}]", result);
             }
         }
         else
         {
             result = "[]";
         }
     }
     catch (Exception)
     {
         throw;
     }

     return result;
 }

创建查询结构类:

   public static QueryStructure CreateQueryStructure(this String value, string endDate, bool isDate,
        string columnName, string whereName, string groupByName, bool isNullField)
    {
        QueryStructure structure = new QueryStructure();

        if (!string.IsNullOrEmpty(value))
        {
            if (value != ",")
            {
                if (isDate)
                {
                    //obtiene la estructura para un filtro entre fechas
                    structure.ColumnSelect = columnName;
                    structure.ColumnGroupBy = groupByName;
                    structure.ColumnWhere = string.Format("({0} BETWEEN convert(datetime,\'{1}\', 103) and convert(datetime,\'{2}\', 103))", whereName, value.Remove(value.Length - 1), endDate.Remove(value.Length - 1));
                    structure.Values = null;
                    structure.Operator = Operator.Nothing;
                }
                else
                {
                    if (isNullField)
                    {
                        //obtiene la estructura de un filtro por un campo que es null o no
                        if (value.Remove(value.Length - 1) != "-1")
                        {
                            structure.ColumnWhere = string.Format("{0} IS{1} NULL", whereName,
                                value.Remove(value.Length - 1) == "0"
                                                                    ? " NOT" :
                                                                    string.Empty);

                            structure.Values = null;
                            structure.Operator = Operator.And;
                        }
                    }
                    else
                    {
                        //obtiene la estructura de un campo aplicando la regla IN seleccionando
                        //el campo a mostrar y el campo en groupBy
                        structure.ColumnSelect = columnName;
                        structure.ColumnGroupBy = groupByName;
                        structure.ColumnWhere = whereName;
                        structure.Values = value.Remove(value.Length - 1);
                        structure.Operator = Operator.And;
                    }
                }
            }
        }

        return structure;
    }

【问题讨论】:

  • 你有什么问题?
  • 对不起,如何在 C# 中向过滤存储过程 XML 添加参数? @罗伯特哈维
  • SQL Server 具有允许您查询 XML 元素的机制。那是你要找的吗? simple-talk.com/sql/learn-sql-server/…
  • 最初使用正确的过滤器正确接收了 xml(我不执行此代码),但我需要更新它。我只想再按一个字段过滤它,但我不太了解它是如何工作的@RobertHarvey
  • 看来您需要修改QueryStructure 中的ColumnWhere 以提供正确的过滤器。

标签: c# sql-server json xml asp.net-mvc


【解决方案1】:

您的错误发生在这里:

structure.Add(initDate.CreateQueryStructure(endDate, true, null, "convert(datetime,'15/' + CONVERT(varchar(10), k.Month) + '/' +  CONVERT(varchar(10), k.Year), 103,k.BranchOfficeId = currentUser)", null, false)

或者,更详细的,在这里:

CONVERT(varchar(10), k.Month) + '/' +  CONVERT(varchar(10), k.Year), 103,k.BranchOfficeId = currentUser)

您正在做的是将您的k.BranchOfficeId = currentUser 作为第四个参数添加到CONVERT-函数。这是一个确定的','附近的语法错误

如果您希望在任何情况下都添加此附加条件,则最简单的方法是将其添加到您以这种方式设置ColumnWhere 的位置:

k.BranchOfficeId = currentUser AND (The other condition you use normally)

但这是您的下一个问题:看起来currentUser 是您应用程序中的一个变量。您必须使用值,而不是名称

有点像

string.Format(" k.BranchOfficeId = {0} AND ({1}) ",currentUser,TheConditionAsItWasBefore)

希望这会有所帮助...

老实说:这看起来很复杂,容易发生 SQL 注入,您可能会在 Code Review 上向人们展示这一点

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-26
    • 1970-01-01
    • 2017-09-26
    • 2013-03-30
    • 2015-11-20
    • 1970-01-01
    相关资源
    最近更新 更多