LINQ匿名型+ MVCビュー
-
03-07-2019 - |
質問
これについて多くの質問を見てきましたが、本当に必要な答えを得ることができませんでした。
かなり大きなWebアプリケーションをWebフォームからMVCに変換していますが、しばらくすると、データをビューに渡す際に問題が発生しました。アクションでコードを実行します:
//This is just an example
ViewData["QProducts"] = from p in db.Products select new{Name = p.Name, Date = p.ToShortDateString() }
ViewData["QUsers"] = from u in db.Users select u;
foreachループを使用して、htmlのオブジェクトを次のように繰り返します。
foreach(var q in (IEnumerable)ViewData["QEvents"])
{
/*Print the data here*/
}
MVCを使用する前にasp:Repeater
を使用しましたが、これはMVCであるため、ASP.NETコントロールを使用できません。
このデータをビューに渡すにはどうすればよいですか?ここでは、匿名型を使用しないという選択肢はありません。 <%#ViewData.Eval()%>
明らかに動作しません。
アイデアはありますか
解決
匿名型ではなく、名前と日付を保持する型を作成します:
public class NameDate
{
public string Name { get; set; }
public DateTime Date { get; set; }
}
次に、Linqクエリでそれを使用します。
from p in db.Products select new NameDate { Name = p.Name, Date = p.Date }
ビューを強く入力してMyView<IEnumerable<NameDate>>
にし、次にforeach ( var nameDate in ViewData.Model )...
他のヒント
少し怠けていると感じたら、ここでこのコードを使用できます...少し長いですが、基本的にはReflectionのラッパーです...
var something = { Name = "Jim", Age = 25 };
AnonymousType type = AnonymousType.Create(something);
//then used...
string name = type.Get<string>("Name");
int age = type.Get<int>("Age", -1 /* optional default value */);
これがコードです...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace Code {
/// <summary>
/// A convenient method of accessing the values of an
/// anonymous type without needing to define a separate class
/// </summary>
public class AnonymousType {
#region Constants
private const string EXCEPTION_MISSING_PARAMETER_INFORMATION =
"Unable to match the parameter '{0}' to a property in the AnonymousType. This could be due to a casting problem or a Property that does not exist.";
private const string EXCEPTION_COULD_NOT_ACCESS_FIELD =
"Unable to find a field named '{0}' (of type {1})";
private const string EXCEPTION_COULD_NOT_ACCESS_FIELD_AT_INDEX =
"Unable to find a field named '{0}' at the requested index (of type {1})";
#endregion
#region Constructors
/// <summary>
/// Creates a new AutoType for methods that return Anonymus types
/// </summary>
public AnonymousType(object type) {
this._Init(type, false);
}
/// <summary>
/// Creates a new AutoType for methods that return Anonymus types and
/// detetrmins if exceptions should be thrown if a type is missing
/// </summary>
public AnonymousType(object type, bool supressErrors) {
this._Init(type, supressErrors);
}
/// <summary>
/// Initalizes the data for the is type
/// </summary>
private void _Init(object type, bool supressErrors) {
this.SupressExceptions = supressErrors;
this.m_Type = type.GetType();
this.m_TypeData = type;
}
#endregion
#region Static Routines
/// <summary>
/// Creates a new Anonymous Type from the provided object data
/// </summary>
public static AnonymousType Create(object data) {
return new AnonymousType(data);
}
/// <summary>
/// Creates a new Anonymous Type from the provided object data
/// </summary>
public static AnonymousType Create(object data, bool supressErrors) {
return new AnonymousType(data, supressErrors);
}
#endregion
#region Private Members
/// <summary>
/// The type that will be accessed via reflection
/// </summary>
private Type m_Type;
/// <summary>
/// The actual typs that is being used
/// </summary>
private object m_TypeData;
#endregion
#region Properties
/// <summary>
/// Determines if errors should be thrown if any casting errors take place
/// </summary>
public bool SupressExceptions { get; set; }
/// <summary>
/// Accessess a property by name and returns an object
/// </summary>
public object this[string property] {
get {
return this.Get<object>(property);
}
}
#endregion
#region Public Methods
/// <summary>
/// Checks if this Anonymous Type has the specified property
/// </summary>
public bool Has(string property) {
return ((m_Type.GetProperty(property) as PropertyInfo) != null);
}
/// <summary>
/// Returns if this Anonymous type has the specified property and that
/// the value matches the type specified
/// </summary>
public bool Has(string property, Type isType) {
//try and get the property
PropertyInfo prop = m_Type.GetProperty(property) as PropertyInfo;
//If this type doesn't exist at all, just return false
if (prop == null) { return false; }
//if it does exist, verify the type
if (prop.PropertyType.Equals(isType)) { return true; }
return false;
}
/// <summary>
/// Returns a type value using the specified type
/// </summary>
public T Get<T>(string property) {
//return this value if needed
PropertyInfo prop = m_Type.GetProperty(property) as PropertyInfo;
try {
return (T)prop.GetValue(this.m_TypeData, null);
}
catch (Exception ex) {
if (this.SupressExceptions) { return default(T); }
throw new Exception(
string.Format(EXCEPTION_COULD_NOT_ACCESS_FIELD, property, typeof(T).Name),
ex
);
}
}
/// <summary>
/// Returns a type value using the specified type
/// </summary>
public T Get<T>(string property, object[] index) {
//return this value if needed
PropertyInfo prop = m_Type.GetProperty(property) as PropertyInfo;
try {
return (T)prop.GetValue(this.m_TypeData, index);
}
catch (Exception ex) {
if (this.SupressExceptions) { return default(T); }
throw new Exception(
string.Format(EXCEPTION_COULD_NOT_ACCESS_FIELD_AT_INDEX, property, typeof(T).Name),
ex
);
}
}
/// <summary>
/// Returns a type value using the specified type but includes a default value
/// if one it missing
/// </summary>
public T Get<T>(string property, T defaultValue) {
//return this value if needed
PropertyInfo prop = m_Type.GetProperty(property) as PropertyInfo;
if (prop == null) { return defaultValue; }
try {
return (T)prop.GetValue(this.m_TypeData, null);
}
catch (Exception ex) {
if (this.SupressExceptions) { return defaultValue; }
throw new Exception(
string.Format(EXCEPTION_COULD_NOT_ACCESS_FIELD, prop, typeof(T).Name),
ex
);
}
}
/// <summary>
/// Accepts a delegate that will use the names of the passed in
/// parameters as properties to map to. If the property does not
/// exist, then the method will fail.
/// </summary>
public void Use<T1>(Action<T1> with) {
//set a default for each of the params
T1 param1 = default(T1);
//get the parameters for this method
var paramList = with.Method.GetParameters();
//update each of the parameters
string paramName = string.Empty;
try {
for (int i = 0; i < paramList.Length; i++) {
//find the correct matching property for this parameter
paramName = paramList[i].Name;
switch (i + 1) {
case 1:
param1 = this.Get<T1>(paramName);
break;
}
}
}
catch (Exception ex) {
throw new ArgumentException(
string.Format(EXCEPTION_MISSING_PARAMETER_INFORMATION, paramName),
ex
);
}
//otherwise, execute the method provided
with(param1);
}
/// <summary>
/// Accepts a delegate that will use the names of the passed in
/// parameters as properties to map to. If the property does not
/// exist, then the method will fail.
/// </summary>
public void Use<T1, T2>(Action<T1, T2> with) {
//set a default for each of the params
T1 param1 = default(T1);
T2 param2 = default(T2);
//get the parameters for this method
var paramList = with.Method.GetParameters();
//update each of the parameters
string paramName = string.Empty;
try {
for (int i = 0; i < paramList.Length; i++) {
//find the correct matching property for this parameter
paramName = paramList[i].Name;
switch (i + 1) {
case 1:
param1 = this.Get<T1>(paramName);
break;
case 2:
param2 = this.Get<T2>(paramName);
break;
}
}
}
catch (Exception ex) {
throw new ArgumentException(
string.Format(EXCEPTION_MISSING_PARAMETER_INFORMATION, paramName),
ex
);
}
//otherwise, execute the method provided
with(param1, param2);
}
/// <summary>
/// Accepts a delegate that will use the names of the passed in
/// parameters as properties to map to. If the property does not
/// exist, then the method will fail.
/// </summary>
public void Use<T1, T2, T3>(Action<T1, T2, T3> with) {
//set a default for each of the params
T1 param1 = default(T1);
T2 param2 = default(T2);
T3 param3 = default(T3);
//get the parameters for this method
var paramList = with.Method.GetParameters();
//update each of the parameters
string paramName = string.Empty;
try {
for (int i = 0; i < paramList.Length; i++) {
//find the correct matching property for this parameter
paramName = paramList[i].Name;
switch (i + 1) {
case 1:
param1 = this.Get<T1>(paramName);
break;
case 2:
param2 = this.Get<T2>(paramName);
break;
case 3:
param3 = this.Get<T3>(paramName);
break;
}
}
}
catch (Exception ex) {
throw new ArgumentException(
string.Format(EXCEPTION_MISSING_PARAMETER_INFORMATION, paramName),
ex
);
}
//otherwise, execute the method provided
with(param1, param2, param3);
}
/// <summary>
/// Accepts a delegate that will use the names of the passed in
/// parameters as properties to map to. If the property does not
/// exist, then the method will fail.
/// </summary>
public void Use<T1, T2, T3, T4>(Action<T1, T2, T3, T4> with) {
//set a default for each of the params
T1 param1 = default(T1);
T2 param2 = default(T2);
T3 param3 = default(T3);
T4 param4 = default(T4);
//get the parameters for this method
var paramList = with.Method.GetParameters();
//update each of the parameters
string paramName = string.Empty;
try {
for (int i = 0; i < paramList.Length; i++) {
//find the correct matching property for this parameter
paramName = paramList[i].Name;
switch (i + 1) {
case 1:
param1 = this.Get<T1>(paramName);
break;
case 2:
param2 = this.Get<T2>(paramName);
break;
case 3:
param3 = this.Get<T3>(paramName);
break;
case 4:
param4 = this.Get<T4>(paramName);
break;
}
}
}
catch (Exception ex) {
throw new ArgumentException(
string.Format(EXCEPTION_MISSING_PARAMETER_INFORMATION, paramName),
ex
);
}
//otherwise, execute the method provided
with(param1, param2, param3, param4);
}
#endregion
#region Working With Arrays
/// <summary>
/// Returns the specified property as an array of AnonymousTypes
/// </summary>
public AnonymousType[] AsArray(string property) {
object[] values = this.Get<object[]>(property);
return values.Select(o => {
if (o is AnonymousType) { return (AnonymousType)o; }
return new AnonymousType(o);
}).ToArray();
}
/// <summary>
/// Performs the specified action on each value in an array of AnonymousTypes
/// </summary>
public void WithEach(string property, Action<AnonymousType> action) {
foreach (AnonymousType value in this.AsArray(property)) {
action(value);
}
}
#endregion
#region Static Methods
/// <summary>
/// Returns the type of data for the provided object
/// </summary>
public static T Get<T>(object data, string property) {
return new AnonymousType(data).Get<T>(property);
}
/// <summary>
/// Returns the type of data for the provided object
/// </summary>
public static T Get<T>(object data, string property, T defaultValue) {
return new AnonymousType(data).Get<T>(property, defaultValue);
}
/// <summary>
/// Returns the type of data for the provided object
/// </summary>
public static AnonymousType[] AsArray(object data, string property) {
return new AnonymousType(data).AsArray(property);
}
/// <summary>
/// Performs the following action on each of the values in the specified
/// property value for a user
/// </summary>
public static void WithEach(object data, string property, Action<AnonymousType> action) {
new AnonymousType(data).WithEach(property, action);
}
#endregion
}
}
明示的にリストに変換し、ViewDataをキャストすることを検討してください:
ViewData["QUsers"] = (from u in db.Users select u).ToList();
foreach(Users u in (List<Users>)ViewData["QUsers"]){
/*Print the data here*/
}
上記のようにViewDataを使用するか、アクション間で渡すTempDataを使用して、いくつかの方法でデータを渡すことができます。 ViewData.Modelを使用して、厳密に型指定されたモデルを含めることもできます。ビューの定義を次のように変更する必要があることに注意してください
ViewPage<User>
優れたリピーターの交換については、 http://www.codeplex.com/MVCContrib を試してください。彼らには役立つグリッドHtmlヘルパーがあります。
1つのプロジェクションを表示するためだけに別のクラスを作成するのを避けたい場合は、次のように辞書を使用することもできます。
from person in personList select new Dictionary<string, string>
{
{ "Name", person.Firstname + " " + person.Lastname },
{ "Id", person.Id.ToString() }
};
ビューページを入力すると、
ViewPage<IEnumerable<Dictionary<string, string>>>
そして、最終的にビューのリストを次のように繰り返します:
<% foreach (Dictionary<string, string> p in (IEnumerable)ViewData.Model)
{ %>
<li> <%=p["Id"] %> - <%= p["Name"] %> </li>
<% } %>
言うまでもなく、欠点はコードが<!> quot; magic strings <!> quot;でいっぱいになり、コンパイル時のチェックがないためにエラーが発生しやすくなることです
MVCからRouteValueDictionaryを使用することはできませんか?
探しているのはViewModelであると思われます: http:// msdn。 microsoft.com/en-us/vs2010trainingcourse_aspnetmvc3fundamentals_topic7.aspx