gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 20:15:55 25 4
gpt4 key购买 nike

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

<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">

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

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[]">

然后该值包含对象类型并且根本没有任何值。所以 modelbinder 变得困惑,一切都崩溃了。有没有更简单的方法将这个值列表绑定(bind)到 View ?

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);
}
}

FilterOutput.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);
}

TestQuery.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>
}

QueryResult.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);
}
}

QueryBuilder.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());
}
}

Extensions.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);
}

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

最佳答案

在您看来,您不需要像那样设置名称,因为您可以使用 HiddenFor为你做那件事。将 View 中的 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)
}

这应该给你正确的标记,这反过来应该有助于默认模型 Binder 将过滤器发送到你的 QueryResultHttpPost方法:).

**编辑:当您绑定(bind)多个值或单个值( intstring ,两者都可以是 Array )时,您最好更改 Value FilterField中的属性(property)类是 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])
}
}

这样一来,虽然它可能看起来不像是世界上最漂亮的代码,但它可以让您免去不得不破解模型绑定(bind)以按照您想要的方式工作的头痛,它只会默认绑定(bind)。

关于c# - 使用 ASP.NET 和 MVC 3,我如何创建隐藏字段,以便以数组作为列表中每个项目的值的列表正确绑定(bind)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10400551/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com