2

In meiner ASP.NET MVC Core-App übergebe ich von einer unten gezeigten Aktionsmethode die Daten von Blogs und die zugehörigen Daten aus der Posts-Tabelle an eine Ansicht als return View(await _context.Blogs.Include(p => p.Posts).ToListAsync()); Seit ich bin Wenn ich Daten von zwei Tabellen übergebe, brauche ich ein ViewModel wie unten gezeigt. Frage: Wie kann ich ViewModel verwenden, um die zugehörigen Daten von meiner Controller Action-Methode zur Ansicht weiterzuleiten?Entity Framework Eager Loading - Daten an ViewModel übergeben

Im folgenden Code erhalte ich die offensichtlichen Fehler:

InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'System.Collections.Generic.List'1[ASP_Core_Blogs.Models.Blog]', but this ViewDataDictionary instance requires a model item of type 'System.Collections.Generic.IList'1[ASP_Core_Blogs.Models.BlogPostViewModels.BlogsWithRelatedPostsViewModel]'.

Modell:

public class BloggingContext : DbContext 
{ 
    public BloggingContext(DbContextOptions<BloggingContext> options) 
     : base(options) 
    { } 

    public DbSet<Blog> Blogs { get; set; } 
    public DbSet<Post> Posts { get; set; } 
} 

public class Blog 
{ 
    public int BlogId { get; set; } 
    public string Url { get; set; } 

    public List<Post> Posts { get; set; } 
} 

public class Post 
{ 
    public int PostId { get; set; } 
    public string Title { get; set; } 
    public string Content { get; set; } 
    public int PostYear { get; set; } 
    public int BlogId { get; set; } 
    public Blog Blog { get; set; } 
} 

-Controller:

[HttpGet] 
public async Task<IActionResult> Test(string returnUrl = null) 
{ 
    ViewData["ReturnUrl"] = returnUrl; 
    return View(await _context.Blogs.Include(p => p.Posts).ToListAsync()); 
} 

Ansichtsmodell:

public class BlogsWithRelatedPostsViewModel 
{ 
    public int BlogID { get; set; } 
    public int PostID { get; set; } 
    public string Url { get; set; } 
    public string Title { get; set; } 
    public string Content { get; set; } 
    public int PostYear { get; set; } 
} 

Ansicht:

@model IList<ASP_Core_Blogs.Models.BlogPostViewModels.BlogsWithRelatedPostsViewModel> 

<div class="row"> 
    <div class="col-md-12"> 
     <form asp-controller="DbRelated" asp-action="EnterGrantNumbers" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post"> 
      <table class="table"> 
       <thead> 
        <tr> 
         <th></th> 
         <th></th> 
         <th>Url</th> 
         <th>Title</th> 
         <th>Content</th> 
        </tr> 
       </thead> 
       <tbody> 
        @for (int t = 0; t < Model.Count; t++) 
        { 
         <tr> 
          <td><input type="hidden" asp-for="@Model[t].BlogID" /></td> 
          <td><input type="hidden" asp-for="@Model[t].PostID" /></td> 
          <td> 
           <input type="text" asp-for="@Model[t].Url" style="border:0;" readonly /> <!--Not using /*Html.DisplayFor(modelItem => Model[t].Url)*/ since it does not submit stateName on Post. Not using <label asp-for=.....> since Bootstrap bold the text of <label> tag--> 
          </td> 
          <td> 
           <input asp-for="@Model[t].Title" /> 
          </td> 
          <td> 
           <input asp-for="@Model[t].Content" /> 
          </td> 
         </tr> 
        } 
       </tbody> 
      </table> 
      <button type="submit" class="btn btn-default">Save</button> 
     </form> 
    </div> 
</div> 

Antwort

1

Sie benötigen eine Abfrage mit Ihrer BlogsWithRelatedPostsViewModel Klasse zu projizieren:

 return View(_context.Blogs 
          .Include(p => p.Posts) 
          .SelectMany(e=> e.Posts.Select(p=> new BlogsWithRelatedPostsViewModel 
                  { 
                   BlogId= e.BlogId, 
                   PostId=p.PostId, 
                   Url=e.Url, 
                   ... 
                  }) 
          .ToList()); 

SelectMany Extension-Methode ermöglicht es Ihnen, jeden Vorsprung abflachen aus e.Posts in einer Sequenz, so am Ende erhalten Sie eine List<BlogsWithRelatedPostsViewModel>

+0

Ich erhalte den Fehler auf 'ToLisAsync()' wie: 'IEnumerable 'enthält keine Definition für 'ToListAsync' und keine Erweiterungsmethode 'ToListAsync' ein erstes Argument vom Typ akzeptieren' IEnumerable 'könnte gefunden werden' – nam

+0

mit 'ToList()' Ich erhalte den Fehler: 'InvalidOperationException: Das in das ViewDataDictionary übergebene Modellelement ist vom Typ 'Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable'1 [ASP_Core_Blogs. Models.BlogPostViewModels.BlogsWithRelatedPostsViewModel] ', aber diese ViewDataDictionary-Instanz benötigt ein Modellelement vom Typ' System.Collections.Generic.List'1 [ASP_Core_Blogs.Models.BlogPostViewModels.BlogsWithRelatedPostsViewModel] '. '.In der @ Model-Direktive der Ansicht habe ich 'IList <...>' in 'List <...>' geändert, bevor dieser Fehler auftritt. – nam

+0

Das macht nicht viel Sinn, es ist so, als ob Sie das Ergebnis Ihrer Abfrage übergeben hätten, ohne jedoch ToList aufzurufen. Sind Sie sicher, dass diese Aktion? – octavioccl

0

Oben auf Octavioccl, Antwort gibt es eine nette kleine Erweiterung Methode, die ich verwendet habe (ich kenne den Autor nicht, aber wenn jemand anderes weiß , Werde ich meine Antwort gerne aktualisieren, um Kredit zu geben). Auf diese Weise müssen Sie nicht jede Eigenschaft ausschreiben.

public static T Cast<T>(this object myobj) 
{ 
    var target = typeof(T); 
    var x = Activator.CreateInstance(target, false); 
    var d = from source in target.GetMembers().ToList() 
      where source.MemberType == MemberTypes.Property 
      select source; 
    var memberInfos = d as MemberInfo[] ?? d.ToArray(); 
    var members = memberInfos.Where(memberInfo => memberInfos.Select(c => c.Name) 
     .ToList().Contains(memberInfo.Name)).ToList(); 
    foreach (var memberInfo in members) 
    { 
     var propertyInfo = typeof(T).GetProperty(memberInfo.Name); 
     if (myobj.GetType().GetProperty(memberInfo.Name) == null) continue; 
     var value = myobj.GetType().GetProperty(memberInfo.Name).GetValue(myobj, null); 
     propertyInfo.SetValue(x, value, null); 
    } 
    return (T)x; 
} 

Verbrauch:

var ViewModelList = ModelList.Select(model => model.Cast<ViewModel>()).ToList(); 

Es gibt auch einen gut Rahmen für dieses spezifische Problem gebaut unterstützt. AutoMapper genannt (http://automapper.org/).

0

Zum Weiterleiten von Daten aus Action, die als ViewModel angezeigt werden. Erstellen Sie zuerst eine neue Instanz Ihres View-Modells und weisen Sie jedem Property einen Wert zu, indem Sie Ihre Kontextabfrage (unabhängig von Ihrer Linq-Abfrage) aufrufen und die Liste der View als View-Modellvariable zurückgeben.

var blogWithRelatedPost = new BolblogWithRelatedPost(); 
// your logic here for assigning value to property or LINQ query 
return View(blogWithRelatedPost); 
Verwandte Themen