2009-01-03 20 views
6

He visto muchas preguntas sobre esto, pero nunca obtuve la respuesta que necesitaba.LINQ Anonymous Types + MVC Views

Estoy convirtiendo una aplicación web bastante grande de Web Forms a MVC y después de un tiempo describí un problema al pasar datos a la vista. En la acción ejecuto el código:

//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;

Puedo usar un bucle foreach para iterar sobre los objetos de HTML, como esto:

foreach(var q in (IEnumerable)ViewData["QEvents"]) 
{ 
    /*Print the data here*/ 
} 

Antes de utilizar MVC acabo de utilizar un asp:Repeater, pero ya que este es MVC, no puedo usar controles ASP.NET.

¿Cómo se supone que debo pasar estos datos a la Vista? Realmente no tengo la opción de no usar los tipos anónimos aquí. <%#ViewData.Eval()%> obviamente no funcionará.

¿Alguna idea?

Respuesta

15

En lugar de un tipo anónimo, crear un tipo para contener el nombre y la fecha:

public class NameDate 
{ 
    public string Name { get; set; } 
    public DateTime Date { get; set; } 
} 

A continuación, el uso que en la consulta LINQ:

from p in db.Products select new NameDate { Name = p.Name, Date = p.Date } 

Fuertemente escriba su fin de ser MyView<IEnumerable<NameDate>> y entonces solo haz un foreach (var nameDate in ViewData.Model)...

+0

Gracias por una buena respuesta. – impClaw

+0

De nada, pero lo siento, olvidé citar el genérico, por lo que no es legible. Lo editará ... –

+1

Entonces, ¿no hay forma de evitar tener que crear una nueva clase? Realmente me gustan los tipos anónimos en estos casos, son una manera rápida y fuertemente tipada de obtener un campo generado y no me gusta crear una clase completamente nueva solo para 1 caso en particular. ¿Hay alguna forma clara de pasar el tipo anónimo a la vista? – emzero

1

bien se puede convertir de forma explícita a una lista y fundición de la ViewData:

ViewData["QUsers"] = (from u in db.Users select u).ToList(); 

foreach(Users u in (List<Users>)ViewData["QUsers"]){ 

    /*Print the data here*/ 

} 

se puede pasar los datos de varias maneras, usando como ViewData que están por encima o TempData pase entre acciones. También puede usar ViewData.Model para contener un modelo fuertemente tipado. Tenga en cuenta que tendrá que cambiar la definición de la vista a ser algo así como

ViewPage<User> 

En cuanto a un reemplazo agradable repetidor tratar http://www.codeplex.com/MVCContrib. Tienen un Grid Html Helper que puede ayudar.

1

Si quieres evitar crear una clase separada solo para mostrar tu proyección, también puedes recurrir al uso un diccionario, así:

from person in personList select new Dictionary<string, string> 
{ 
    { "Name", person.Firstname + " " + person.Lastname }, 
    { "Id", person.Id.ToString() } 
}; 

continuación, puede escribir el ViewPage a

ViewPage<IEnumerable<Dictionary<string, string>>> 

Y finalmente iterar sobre la lista en la vista de este modo:

<% foreach (Dictionary<string, string> p in (IEnumerable)ViewData.Model) 
{ %> 
    <li> <%=p["Id"] %> - <%= p["Name"] %> </li> 
<% } %> 

Ni que decir tiene, El inconveniente es que su código ahora está bastante lleno de "cadenas mágicas", por lo que es más propenso a errores debido a la ausencia de comprobación de tiempo de compilación.

2

Si te sientes un poco flojo, puedes usar este código aquí ... Es un poco largo, pero básicamente es un envoltorio para 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 */); 

Y aquí está el código ...

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 

    } 
} 
0

no puedes utilizar el RouteValueDictionary de MVC?