我刚刚开始使用ASP.NET MVC,因为它处于测试阶段。在我的代码中,我正在运行一个简单的LINQ to SQL查询来获取结果列表并将其传递给我的视图。这种事情:
var ords = from o in db.Orders
where o.OrderDate == DateTime.Today
select o;
return View(ords);
但是,在我的视图中,我意识到我需要访问每个订单的客户名称。我开始使用o.Customer.Name
,但我很确定这是为每个订单执行一个单独的查询(因为LINQ的延迟加载)。
减少查询数量的合理方法是同时选择客户名称。类似的东西:
var ords = from o in db.Orders
from c in db.Customers
where o.OrderDate == DateTime.Today
and o.CustomerID == c.CustomerID
select new { o.OrderID, /* ... */, c.CustomerName };
return View(ords);
现在我的“ords”变量是一个匿名类型的IEnumerable。
是否可以以这样的方式声明ASP.NET MVC视图:它接受IEnumerable作为其视图数据,其中T由从控制器传递的内容定义,或者我是否必须定义填充的具体类型从我的查询?
答案 0 :(得分:22)
你能把它传递给视图吗?是的,但您的视图不会被强类型化。但帮手会工作。例如:
public ActionResult Foo() {
return View(new {Something="Hey, it worked!"});
}
//Using a normal ViewPage
<%= Html.TextBox("Something") %>
该文本框应呈现“嘿,它有效!”作为价值。
那么你可以定义一个视图,其中T是由从控制器传递给它的内容定义的吗?是的,但显然不是在编译时。
考虑一下。当您为视图声明模型类型时,您将获得视图的智能感知。这意味着必须在编译时确定类型。但问题是,我们可以在运行时从给定的东西中确定类型。当然,但没有强大的打字保留。
你怎么会得到一个你还不知道的智能感知器?控制器最终可以在运行时将任何类型传递给视图。我们甚至无法分析代码和猜测,因为动作过滤器可以为我们所知道的所有人改变传递给视图的对象。
我希望能够澄清答案而不会使其更加模糊。 :)
答案 1 :(得分:11)
你可以将匿名类型传递给视图,只需记住将模型转换为动态模型。
你可以这样做:
return View(new {
MyItem = "Hello",
SomethingElse = 42,
Third = new MyClass(42, "Yes") })
在视图的顶部,您可以执行此操作(在此使用剃刀)
@{
string myItem = (dynamic)Model.MyItem;
int somethingElse = (dynamic)Model.SomethingElse;
MyClass third = (dynamic)Model.Third;
}
或者您可以像这样从ViewData中投射它们:
@{
var myItem = ViewData.Eval("MyItem") as string
var somethingElse = ViewData.Eval("SomethingElse") as int?
var third = ViewData.Eval("Third") as MyClass
}
答案 2 :(得分:7)
在.NET 4.0上,匿名类型可以很容易地转换为ExpandoObjects,因此所有问题都可以通过转换本身的开销来解决。 查看here
答案 3 :(得分:4)
为了它的价值,今晚我发现了DataLoadOptions类及其LoadWith方法。每当检索到Orders行时,我能够告诉我的LINQ to SQL DataContext始终加载Customers行,因此原始查询现在可以在一次点击中获得我需要的所有内容。
答案 4 :(得分:3)
Here是一篇文章,解释了如何将匿名类型传递给视图并绑定数据。
由于
答案 5 :(得分:1)
这个post显示了如何从方法中返回匿名类型,但它不符合您的要求。
另一个选择可能是将匿名类型转换为JSON(JavaScriptSerializer会这样做),然后将该JSON返回到视图,然后你需要一些jQuery等来做你喜欢的事情。
我一直在使用Linq将我的数据“塑造”成JSON格式,我的观点非常成功。
答案 6 :(得分:1)
您可以编写一个具有匿名类型相同属性的类,并且可以将您的匿名类型转换为手写类型。缺点是在linq查询中进行投影更改时必须更新类。
答案 7 :(得分:0)
您可以传递一个Object并使用反射来获得所需的结果。看一下ObjectDumper.cs(包含在csharpexamples.zip中)的一个例子。
答案 8 :(得分:0)
如果我没弄错的话,匿名类型会在编译时转换为强类型对象。强类型对象是否对视图数据有效是另一个问题。
答案 9 :(得分:0)
我遇到了同样的问题......经过一番思考后,我得出的结论是最正确,最具扩展性的解决方案,它是在发送到View之前序列化这个匿名类型。因此,您可以使用相同的方法使用后面的View代码填充页面并使用JSON填充页面
答案 10 :(得分:0)
请记住: anonymous
类型是内部的,这意味着它们的属性无法在其定义的程序集之外看到。
通过将dynamic
类型转换为anonymous
,您可以更好地将View
个对象(而不是anonymous
个)传递给dynamic
扩展方法。
public class AwesomeController : Controller
{
// Other actions omitted...
public ActionResult SlotCreationSucceeded(string email, string roles)
{
return View("SlotCreationSucceeded", new { email, roles }.ToDynamic());
}
}
扩展方法如下所示:
public static class DynamicExtensions
{
public static dynamic ToDynamic(this object value)
{
IDictionary<string, object> expando = new ExpandoObject();
foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType()))
expando.Add(property.Name, property.GetValue(value));
return (ExpandoObject) expando;
}
}
尽管如此,仍然可以传递anonymous
个对象,但您必须将其转换为dynamic
一个。
public class AwesomeController : Controller
{
// Other actions omitted...
public ActionResult SlotCreationSucceeded(string email, string roles)
{
return View("SlotCreationSucceeded", new { email, roles });
}
}
查看:强>
@{
var anonymousModel = DynamicUtil.ToAnonymous(Model, new { email = default(string), roles = default(string) });
}
<h1>@anonymousModel.email</h1>
<h2>@anonymousModel.roles</h2>
辅助方法如下所示:
public class DynamicUtil
{
public static T ToAnonymous<T>(ExpandoObject source, T sample)
where T : class
{
var dict = (IDictionary<string, object>) source;
var ctor = sample.GetType().GetConstructors().Single();
var parameters = ctor.GetParameters();
var parameterValues = parameters.Select(p => dict[p.Name]).ToArray();
return (T) ctor.Invoke(parameterValues);
}
}