2009-01-03 6 views
6

Ich habe viele Fragen dazu gesehen, aber ich habe nie wirklich die Antwort bekommen, die ich brauche.LINQ Anonyme Typen + MVC Ansichten

Ich konvertiere eine ziemlich große Web-Anwendung von Web Forms zu MVC und nach einer Weile habe ich ein Problem mit der Übergabe von Daten an die Ansicht. In der Aktion ausführen ich den Code:

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

ich eine foreach-Schleife über die Objekte in HTML iterieren, wie folgt aus:

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

Vor der Verwendung von MVC habe ich nur eine asp:Repeater, aber Da dies MVC ist, kann ich keine ASP.NET-Steuerelemente verwenden.

Wie soll ich diese Daten an die View übergeben? Ich habe nicht wirklich die Möglichkeit, anonyme Typen hier nicht zu verwenden. <%#ViewData.Eval()%> wird offensichtlich nicht funktionieren.

Irgendwelche Ideen?

Antwort

15

Anstatt ein anonymer Typ, eine Art erstellen Sie den Namen und das Datum zu halten:

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

dann verwenden, in Ihren Linq query:

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

Stark Ihre Ansicht eine MyView<IEnumerable<NameDate>> zu sein und dann tun Sie einfach einen foreach (var nameDate in ViewData.Model)...

+0

Dank für eine gute Antwort. – impClaw

+0

Gern geschehen - aber leider habe ich vergessen, das Generische zu zitieren, damit es nicht lesbar ist. Wird es bearbeiten ... –

+1

Also gibt es keine Möglichkeit zu vermeiden, eine neue Klasse zu erstellen? Ich mag anonyme Typen in diesen Fällen, sie sind eine schnelle und stark typisierte Art, ein generiertes Feld zu bekommen, und ich mag es nicht, eine ganz neue Klasse nur für einen bestimmten Fall zu erstellen. Gibt es eine saubere Möglichkeit, den anonymen Typ an die Ansicht zu übergeben? – emzero

1

Betrachten wir explizit auf eine Liste konvertieren und das Viewdata Gießen:

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

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

    /*Print the data here*/ 

} 

Sie können Daten in ein paar Möglichkeiten passieren, mit Viewdata, wie Sie oben sind, oder TempData zwischen Aktionen zu übergeben. Sie können ViewData.Model auch verwenden, um ein stark typisiertes Modell zu enthalten. Beachten Sie, dass Sie so etwas wie

ViewPage<User> 

Wie für einen schönen Repeater Ersatz sein müssen, um die Definition der Ansicht ändern http://www.codeplex.com/MVCContrib versuchen. Sie haben einen Grid Html Helper, der Ihnen helfen kann.

1

Wenn Sie vermeiden möchten, eine separate Klasse nur für die Anzeige Ihrer einen Projektion zu erstellen, können Sie auch auf die Verwendung zurückgreifen ein Wörterbuch, etwa so:

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

Sie können Ihre viewpage zu

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

Und schließlich iterieren der Liste in der Ansicht wie so geben Sie dann:

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

Unnötig zu sagen, Der Nachteil ist, dass Ihr Code jetzt ziemlich voll von "magischen Zeichenfolgen" ist, was ihn aufgrund der fehlenden Kompilierzeitprüfung fehleranfälliger macht.

2

Wenn Sie ein wenig faul sind, können Sie diesen Code hier verwenden ... Es ist ein wenig lang, aber im Grunde ist es ein Wrapper für 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 */); 

Und hier ist der Code ...

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

Kannst du nicht einfach die Routevaluedictionary von MVC verwenden?