简体   繁体   中英

Passing joined table to view as model Asp.Net Core

I have 2 tables that I join via linq query:

var catData = from c in _context.ProductCategory
              join d in _context.ProductCategoryData
                     on c.Id equals d.ProductCategoryId into g
              from gg in g.DefaultIfEmpty()
              select new { c.Id, c.Name, gg.Path };

I want to pass result of this query as model to view. The issue is that view requires strongly specified type of model I'm passing.

I've heard that it's possible to introduce another class which will contain 2 table models and then join 2 tables into this class. However, in my opinion it's not efficient since I will always have all columns from both tables while I need only particular columns.

Another option that came to my mind - to use ExpandoObject like below:

dynamic model = new ExpandoObject();
model = catData.ToList();

return View("Categories", model);

And then access dynamic object in view like this:

@model dynamic;

@foreach (var i in Model)
{
   <img src="@i.Path">
       <p>@i.Name</p>
}

However this throws an error that Model object doesn't contain Path or Name.

Is there any other way to solve this?

The best way is create a new CatData and ViewModel classes

public class CatData
{
public int Id {get; set;}
public string Name {get; set;}
public string Path {get; set;}
}

public class CatDataViewModel
{
  public IEnumerable<CatData> CatDataList {get; set;}
}

fix your query

var catData = ( from ...
              select new CatData { Id= c.Id, Name =c.Name, Path= gg.Path }
              ).ToList();

var model= new CatDataViewModel { CatDataList=catData };

and view

@model CatDataViewModel;

@foreach (var i in Model.CatDataList)
{
   <img src="@i.Path">
       <p>@i.Name</p>
}

What you need is an IEnumerable<dynamic> not a dynamic . dynamic works only as an object exposing properties/methods and cannot be an IEnumerable of arbitrary objects. As you can see the ExpandoObject is actually an IEnumerable of key-value pairs (map between member names & member values). But that's not kind of IEnumerable you want.

This code:

dynamic model = new ExpandoObject();
model = catData.ToList();

actually will set back your model to a list of { c.Id, c.Name, gg.Path } . So it's not dynamic as you thought.

Here's how you can build an IEnumerable<dynamic> :

var model = catData.Select(e => {
               dynamic o = new ExpandoObject();
               o.Id = e.Id;
               o.Name = e.Name;
               o.Path = e.Path;
               return o;
            });

The model then is a true IEnumerable<dynamic> and it should work now.

You can also write an extension method to convert a normal IEnumerable<T> to IEnumerable<dynamic> to use this special scenario like this:

public static class DynamicEnumerableExtensions {
     public static IEnumerable<dynamic> AsDynamic<T>(this IEnumerable<T> items) {
            var props = typeof(T).GetProperties();
            foreach(var item in items)
            {
                var o = new ExpandoObject();
                //set properties for the dynamic item
                foreach(var prop in props)
                {
                    o.TryAdd(prop.Name, prop.GetValue(item));
                }
                yield return o;
            }
     }
}

And use it like this:

var model = catData.AsDynamic();

With that convenient method, you will not have to manually rewrite the logic every time such as for a new list of arbitrary anonymous objects (with unknown number of properties).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM