使用 ASP.NET 和 MVC 3,如何创建隐藏字段,以便正确绑定以数组作为列表中每个项目的值的列表?

2024-03-11

我有一个查询语句列表,当需要在末尾添加另一个语句时,需要将这些查询语句发回 MVC 控制器。对于我现在尝试创建的测试,页面以过滤器列表开头。执行此示例时,页面将为过滤器创建字段,如下所示:

<input id="filters_0__PropertyName" name="filters[0].PropertyName" type="hidden" value="State">
<input id="filters_0__Operator" name="filters[0].Operator" type="hidden" value="=">
<input id="filters_0__Value" name="filters[0].Value" type="hidden" value="CA">

但是当我看到表单实际发回控制器时,列表返回为:

PropertyName = "State"
Operator = "="
Value= "new string[1]" // The value comes back in the first index of the array

我必须将值参数转换为数组并采用第一个索引才能获取值。这还可以,但并不理想。当 FilterField 包含 Value 属性的整数或字符串数​​组时,主要问题就出现了。当这种情况发生时,HTML 会显示为:

<input id="filters_2__PropertyName" name="filters[3].PropertyName" type="hidden" value="Schedule_Num">
<input id="filters_2__Operator" name="filters[3].Operator" type="hidden" value="IN">
<input id="filters_2__Value" name="filters[3].Value" type="hidden" value="System.Int32[]">

然后,该值包含对象类型,但根本不包含任何值。所以模型绑定器会变得混乱并且一切都会崩溃。有没有更简单的方法将此值列表绑定到视图?

FilterField.cs:

public class FilterField
{
    public string PropertyName { get; set; }
    public string Operator { get; set; }
    public object Value { get; set; }

    public FilterOutput GetOutput()
    {
        return new FilterOutput(PropertyName, Operator, Value);
    }
}

过滤器输出.cs

public class FilterOutput
{
    private List<QueryProperty> _properties = new List<QueryProperty>();
    private string _propertyName;
    private string _op;
    private object _value;

    public string Sql { get; set; }
    public QueryProperty[] Properties { get; set; }

    public FilterOutput(string propertyName, string op, object value)
    {
        var sql = "[{0}] {1} {2}";
        Sql = string.Format(sql, propertyName, op, FormatParameter(propertyName, op, value));
        Properties = _properties.ToArray();
    }

    private string FormatParameter(string propertyName, string op, object value)
    {
        _properties.Clear();
        var sb = new StringBuilder();
        switch (op.ToUpper())
        {
            case "IN":
                {
                    var values = value as Array;
                    sb.Append("{");
                    var inCount = 0;
                    foreach (var v in values)
                    {
                        var pName = propertyName + inCount;
                        if (inCount == 0)
                            sb.Append("@" + pName);
                        else
                            sb.Append(",@" + pName);
                        _properties.Add(new QueryProperty { Name = pName, Value = v });
                        inCount++;
                    }
                    sb.Append("}");
                }
                break;
            case "LIKE":
                if (value.ToString().Contains("_"))
                    sb.Append("@" + propertyName);
                else
                    sb.Append("'%' + @" + propertyName + " + '%'");
                _properties.Add(new QueryProperty { Name = propertyName, Value = value });
                break;
            case "BETWEEN":
                var range = value as Array;
                var betweenCount = 0;
                foreach (var r in range)
                {
                    if (betweenCount > 0)
                        sb.Append(" AND ");
                    sb.Append("@" + propertyName + betweenCount);
                    _properties.Add(new QueryProperty { Name = propertyName + betweenCount, Value = r });
                    betweenCount++;
                }
                break;
            default:
                sb.Append("@" + propertyName);
                _properties.Add(new QueryProperty { Name = propertyName, Value = value });
                break;
        }
        return sb.ToString();
    }

    public string ConvertToSql()
    {
        var filterOutput = this;
        var output = filterOutput.Properties.Aggregate(filterOutput.Sql, (current, p) => current.Replace("@" + p.Name, FormatObjectToString(p.Value)));
        output = output
            .Replace("[", "t.").Replace("]", "") // Convert [text] to t.text
            .Replace("{", "(").Replace("}", ")") // Convert {'text1','text2'} to ('text1','text2')
            .Replace("'%' + '", "'%").Replace("' + '%'", "%'"); // Convert '%' + text + '%' to '%text%'
        return " AND " + output;
    }

    public override string ToString()
    {
        var filterOutput = this;
        return filterOutput.Properties.Aggregate(filterOutput.Sql, (current, p) => current.Replace("@" + p.Name, FormatObjectToString(p.Value)).Replace("'%' + '", "'%").Replace("' + '%'", "%'"));
    }

    private string FormatObjectToString(object value)
    {
        if (value is int)
            return value.ToString();
        return String.Format("'{0}'", value);
    }
}

HomeController.cs

public ActionResult TestQuery(DateTime date)
{
    var builder = new QueryBuilder(_repo, "INFO", date);

    builder.AddFilters(
            new FilterField
                {
                    PropertyName = "State",
                    Operator = "=",
                    Value = "CA"
                },
            new FilterField
                {
                    PropertyName = "Schedule_Num",
                    Operator = "IN",
                    Value = new[] {2, 6}
                });

    var result = builder.Build();
    return View(result);
 }

 [HttpPost]
 public ActionResult TestPost(QueryResult result)
 {
    var builder = new QueryBuilder(_repo, "INFO", date);

    foreach (var f in result.Filters)
    {
        builder.AddFilters(new FilterField
                                   {
                                       PropertyName = f.PropertyName,
                                       Operator = f.Operator,
                                       Value = ((Array)f.Value).GetValue(0)
                                   });
    }

    builder.AddFilters(
            new FilterField
                {
                    PropertyName = "Gender",
                    Operator = "BETWEEN",
                    Value = new[] {"A", "G"}
                });

    var newResult = builder.Build();
    return View("TestQuery", newResult);
 }

测试查询.cshtml

@model Models.QueryResult

@using (Html.BeginForm("TestPost", "Home"))
{
    @Html.HiddenFor(m => m.Date)
    for (var i = 0; i < Model.Filters.Count(); i++)
    {
        @Html.Hidden("filters[" + i + "].PropertyName", Model.Filters[i].PropertyName)
        @Html.Hidden("filters[" + i + "].Operator", Model.Filters[i].Operator)
        @Html.Hidden("filters[" + i + "].Value", Model.Filters[i].Value)
    }
    <div class="formArea">
        <p>
            <input type="submit" value="Submit" id="btnSubmit" />
        </p>
    </div>
}

查询结果.cs

public class QueryResult
{
    public DateTime Date { get; set; }
    public ObjectQuery<EntityObject> Objects { get; set; }
    public string SqlStatement { get; set; }
    public ObjectParameter[] Parameters { get; set; }
    public AdjustResult AdjustResult { get; set; }
    public IList<FilterField> Filters { get; set; }

    public QueryResult()
    {
        Filters = new List<FilterField>();
    }

    public void AddFilter(FilterField filter)
    {
        Filters.Add(filter);
    }

    public string ParsedSqlStatement()
    {
        var output = Parameters.Aggregate(SqlStatement, (current, p) => current.Replace("@" + p.Name, FormatObjectToString(p.Value)));
        return Filters.Aggregate(output, (current, filter) => current + filter.ConvertToSql());
    }

    private string FormatObjectToString(object value)
    {
        if (value is int)
            return value.ToString();
        return String.Format("'{0}'", value);
    }
}

查询生成器.cs

public class QueryBuilder
{
    public IList<FilterField> Filters { get; set; }

    private IDynamicRepository _repo;
    private string _tablePrefix;
    private DateTime _date;
    private QueryResult _base;

    public QueryBuilder(IDynamicRepository repository, string tablePrefix, DateTime date)
    {
        _repo = repository;
        _tablePrefix = tablePrefix;
        _date = date;
        _base = _repo.GetAll(tablePrefix, date);
        Filters = new List<FilterField>();
    }

    public void AddFilters(params FilterField[] filters)
    {
        foreach (var f in filters)
        {
           Filters.Add(f);
        }
    }

    public void RemoveFilter(FilterField filter)
    {
        Filters.Remove(filter);
    }

    public QueryResult Build()
    {
        return _base.Where(Filters.ToArray());
    }
}

扩展.cs

public static QueryResult Where(this QueryResult result, string predicate, params QueryProperty[] properties)
{
    result.Objects = result.Objects.Where(predicate.ReplaceIdentifier(), properties.Select(p => new ObjectParameter(p.Name, p.Value)).ToArray());
    return result;
}

public static QueryResult Where(this QueryResult result, FilterField filter)
{
    var filterOutput = filter.GetOutput();
    result.Objects = result.Objects.Where(filterOutput.Sql.ReplaceIdentifier(), filterOutput.Properties.Select(p => new ObjectParameter(p.Name, p.Value)).ToArray());
    result.AddFilter(filter);
    return result;
}

public static QueryResult Where(this QueryResult result, params FilterField[] filters)
{
    return filters.Aggregate(result, Where);
}

由于有些人想了解更多信息,这里有一些有关所有内容如何联系在一起的更多详细信息。基本上,控制器从 UI 获取过滤器列表,这些过滤器可归结为 WHERE 之后的 SQL 语句。因此,一个过滤器将变成 FIELD = VALUE 或 FIELD IN (VALUE1, VALUE2)。查询生成器使用 Entity.CreateQuery("SELECT * FROM TABLE") 创建 SQL 语句的基础。一旦运行了 querybuilder 上的 Build() 方法,它就会创建一个 QueryResult 模型,其中包含查询的日期以及带有附加过滤器的查询的所有 EntityObjects,这些实体对象将转换为与视图一起使用的 WHERE 语句。我继续添加了更多的类来展示它们是如何联系在一起的。


在您看来,您不需要这样设置名称,因为您可以使用HiddenFor为你做到这一点。将视图中的 for 循环更改为:

for (var i = 0; i < Model.Filters.Count(); i++)
{
    @Html.HiddenFor(m => m.Filters[i].PropertyName)
    @Html.HiddenFor(m => m.Filters[i].Operator)
    @Html.HiddenFor(m => m.Filters[i].Value)
}

这应该为您提供正确的标记,这反过来又应该帮助默认模型绑定器将过滤器发送到您的QueryResult in the HttpPost方法 :)。

**编辑:当您绑定多个值或单个值时(int or string,两者都可以是Array),你最好改变Value财产在FilterField类成为List<string>.

所以,在FilterField类替换这个:

public object Value { get; set; }

有了这个:

public List<string> Values { get; set; }

然后将您的标记更改为:

for (var i = 0; i < Model.Filters.Count(); i++)
{
    @Html.HiddenFor(m => m.Filters[i].PropertyName)
    @Html.HiddenFor(m => m.Filters[i].Operator)
    for (var j = 0; j < Model.Filters[i].Values.Count; j++)
    {
        @Html.HiddenFor(m => m.Filters[i].Values[j])
    }
}

这样,虽然它可能看起来不是世界上最漂亮的代码,但它可以让您免去必须修改模型绑定以按照您想要的方式工作的麻烦,它只会默认绑定。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 ASP.NET 和 MVC 3,如何创建隐藏字段,以便正确绑定以数组作为列表中每个项目的值的列表? 的相关文章

  • C# 正则表达式用于查找 中具有特定结尾的链接

    我需要一个正则表达式模式来查找字符串 带有 HTML 代码 中的链接 以获取文件结尾如 gif 或 png 的链接 示例字符串 a href site com folder picture png target blank picture
  • 将字符串中的“奇怪”字符转换为罗马字符

    我需要能够将用户输入仅转换为 a z 罗马字符 不区分大小写 所以 我感兴趣的角色只有26个 然而 用户可以输入他们想要的任何 形式 的字符 西班牙语 n 法语 e 和德语 u 都可以包含用户输入中的重音符号 这些重音符号会被程序删除 我已
  • C++中delete和delete[]的区别[重复]

    这个问题在这里已经有答案了 可能的重复 C 中的删除与删除 运算符 https stackoverflow com questions 2425728 delete vs delete operators in c 我写了一个包含两个指针的
  • 选择列表逻辑应位于 ASP.NET MVC、视图、模型或控制器中的什么位置?

    我觉得我的问题与这个问题很接近 但我想对这样的代码应该放在哪里进行更一般的讨论 Asp Net MVC SelectList 重构问题 https stackoverflow com questions 2149855 asp net mv
  • mprotect 之后 malloc 导致分段错误

    在使用 mprotect 保护内存区域后第一次调用 malloc 时 我遇到分段错误 这是执行内存分配和保护的代码片段 define PAGESIZE 4096 void paalloc int size Allocates and ali
  • 劫持系统调用

    我正在编写一个内核模块 我需要劫持 包装一些系统调用 我正在暴力破解 sys call table 地址 并使用 cr0 来禁用 启用页面保护 到目前为止一切顺利 一旦完成 我将公开整个代码 因此如果有人愿意 我可以更新这个问题 无论如何
  • 将带有 glut 的点击坐标添加到向量链接列表中

    我想创建一个向量链接列表 并在 GLUT 库的帮助下获取点击的位置并将它们附加到链接列表中 这些是我写的结构 typedef struct vector int x int y Vector typedef struct VectorLis
  • 两种类型的回发事件

    1 我发现了两篇文章 每篇文章对两种类型的回发事件的分类都略有不同 一位资源说两种类型的回发事件是Changed事件 其中控件实现 IPostbackDataHandler 当数据在回发之间更改时触发 然后Raised事件 其中控件实现 I
  • 从 Code::Blocks 运行程序时出现空白控制台窗口 [重复]

    这个问题在这里已经有答案了 当我尝试在 Code Blocks 中构建并运行新程序时 控制台窗口弹出空白 我必须单击退出按钮才能停止它 它对我尝试过的任何新项目 包括 Hello world 都执行此操作 奇怪的是 它对于我拥有的任何旧项目
  • 为什么具有相同名称但不同签名的多个继承函数不会被视为重载函数?

    以下代码片段在编译期间产生 对 foo 的调用不明确 错误 我想知道是否有任何方法可以解决此问题而不完全限定对 foo 的调用 include
  • 二叉树中的 BFS

    我正在尝试编写二叉树中广度优先搜索的代码 我已将所有数据存储在队列中 但我不知道如何访问所有节点并消耗它们的所有子节点 这是我的 C 代码 void breadthFirstSearch btree bt queue q if bt NUL
  • 从 R 到 C 处理列表并访问它

    我想使用从 R 获得的 C 列表 我意识到这个问题与此非常相似 使用 call 在 R 和 C 之间传递数据帧 https stackoverflow com questions 6658168 passing a data frame f
  • WPF。如何从另一个窗口隐藏/显示主窗口

    我有两个窗口 MainWindow 和 Login 显示登录的按钮位于主窗口 this Hide Login li new Login li Show 登录窗口上有一个检查密码的按钮 如果密码正确 我如何显示主窗口 将参数传递给 MainW
  • 使用 mingw32 在 Windows 上构建 glew 时“DllMainCRTStartup@12”的多个定义

    我关注了这个主题 使用 mingw 使建筑物在 Windows 上闪闪发光 https stackoverflow com questions 6005076 building glew on windows with mingw 6005
  • 0-1背包算法

    以下 0 1 背包问题是否可解 浮动 正值和 浮动 权重 可以是正数或负数 背包的 浮动 容量 gt 0 我平均有 这是一个相对简单的二进制程序 我建议用蛮力进行修剪 如果任何时候你超过了允许的重量 你不需要尝试其他物品的组合 你可以丢弃整
  • 使用 javascript/jquery 从数据库格式化日期的正确方法

    我正在调用包含日期时间数据类型的数据库 日期看起来像这样 2005 05 23 16 06 00 000 当用户从列表中选择某个项目时 我想在表格中显示它 我调用我的控制器操作并返回所有时间的 Json 并将它们放入表中 问题是日期完全错误
  • 使用 iTextSharp 5.3.3 和 USB 令牌签署 PDF

    我是 iTextSharp 和 StackOverFlow 的新手 我正在尝试使用外部 USB 令牌在 C 中签署 PDF 我尝试使用从互联网上挖掘的以下代码 Org BouncyCastle X509 X509CertificatePar
  • 在 C++17 中使用 成员的链接错误

    我在 Ubuntu 16 04 上使用 gcc 7 2 并且需要使用 C 17 中的新文件系统库 尽管确实有一个名为experimental filesystem的库 但我无法使用它的任何成员 例如 当我尝试编译此文件时 include
  • 受限 AppDomain 中的代码访问安全异常

    Goal 我需要在权限非常有限的 AppDomain 中运行一些代码 它不应该访问任何花哨或不安全的内容 except对于我在其他地方定义的一些辅助方法 我做了什么 我正在创建一个具有所需基本权限的沙箱 AppDomain 并创建一个运行代
  • 类中不允许使用不完整类型,但类模板中允许使用不完整类型

    以下为无效代码 struct foo struct bar bar x error field x has incomplete type struct bar int value 42 int main return foo x valu

随机推荐