1

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?
1

2 Answers 2

2
  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>
}
Sign up to request clarification or add additional context in comments.

9 Comments

what do you mean by easy to read. Will there be a difference in sql generated in case of theninclude??
The sql generated is the same. But using ThenInclude is a best practice. To get better performance, consider reading: stackoverflow.com/questions/59837585/…
Above is just an example i have relationship with atleast 7 different entities. To rephrase my question can i return column of my choice( which icalled view model) by using something like rawsql etc
Of course. I am editting this answer and will tell you how to return columns on your choice.
As for raw sql query, consider reading: learn.microsoft.com/en-us/ef/core/querying/raw-sql
|
2

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.