简体   繁体   中英

Can Entity Framework Core return view model

I have a situation which can be explained by below analogy.

Example: let's say we have 3 tables Categories => SubCategories => Products .

1 category can have many subcategories and 1 subcategory can have many products.

I am showing simple card for products details with category and subcategory names but for it I am writing the EF like.

var products = await _context.Products
                             .Where(x => x.IsDeleted == false)
                             .Include(x => x.SubCategory)
                             .Include(x => x.SubCategory.Category).ToListAsync()

The SQL generated is too expensive.

When the products are reached to the controller then Automapper starts it's magic to map according to my required view model.

I am new to Entity Framework Core and I have three questions:

  1. Is it there a better way to write above code?
  2. Can I return a view model directly from Entity Framework Core? In the above case, can I return a model with properties showing just names of Products, SubCategory and Category?
  3. If I can't return, then how can I convince myself to stop using Dapper?

Automapper can generate the sql for you, basically doing the mapping to your viewmodel/DTO in the database.

Use the ProjectTo extension to IQueryable , explained here .

  1. Yes. You can use the ThenInclude operation to make the code easier to read.
var products = await _context.Products.Where(x => x.IsDeleted == false)
                                       .Include(x => x.SubCategory)
                                       .ThenInclude(x => x.Category).ToListAsync()
  1. Yes or no. It depends on what your ViewModel is.

Entity framework is a framework for operating database entities. But ViewModel is a concept in MVVM. It was two different concepts and have no relationship.

Usually, the view is rendering what is needed to be rendered. So we return it a ViewModel instead of Entity . If the Entity itself is what you need to be rendered, just return it! It's ok.

return View(viewName: "myview", model: products);
@model IEnumerable<Product> // Product is your entity in EF. You can use it in a view.

It's fine.

But, consider what the view needs is not what you got from entit-framework. Now you need to convert the entity to the ViewModel . For example:

var entity = await dbContext.MyTable.SingleOrDefaultAsync(t => t.Id == id);
var viewModel = new MyViewModel
{
    Color = entity.Color // Only need to return the color, for example.
}
return View(viewModel);
@model MyViewModel

<h2>The color of it is @Model.Color</h2>
@*You can't access other properties of the entity here in the view.*@

And the other properties will not be returned to the view.

And some tools like AutoMapper can just help you do the map job.

Another way is to use Select() to return the column on your choice. For example:

Entity definition and view model definition.

public class Product
{
    public int Id { get; set; } // Don't want to return this.
    public string Name { get; set; } // Only want to return this.
}

public class ProductDto
{
    public string Name { get; set; }
}
var products = _context.Products; // While the products is declared, the query was not happened in the database. It only defines an IQueryable object.
List<ProductDto> viewModel = await products.Select(t => new ProductDto
{
    Name = t.Name // Manually map here.
})
.ToListAsync();

return View(viewModel);

In your view:

@model List<ProductDto>
foreach (var dto in Model)
{
  <h2>dto.Name</h2>
}

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