score:2
Separate your concerns. Entities represent domain models. DTOs represent view or consumer models. While EF deals extensively with IQueryable
, your consumers don't typically need IQueryable
, most of the time they just need to be able to enumerate over the results, so IEnumerable
is sufficient. Even within Entities, I don't represent relationships between entities with IQueryable
, instead I use ICollection
.
IQueryable
is a structure to indicate that Linq expressions should be passed through to the source of the data. For EF Linq operations that allows Linq expressions to translated down to SQL. When it comes to dealing with consuming data that has been returned, you can use Linq against IEnumerable
and the like still if you need to further filter or translate results. Entities should never really be passed outside of the scope of their DbContext as features like lazy loading requires the DbContext to be alive, and you cannot reliably assume lazy loads would never be tripped by a consuming view or serializer etc. Entities are data state, view state should be kept separate.
Given a domain model of entities consisting of Boards, BoardLists, and Cards my entities would look something like:
public class Board
{
public int BoardId { get; set; }
public string Name { get; set; }
public virtual ICollection<BoardList> Lists { get; set; } = new List<BoardList>();
}
public class BoardList
{
public int BoardListId { get; set; }
public string Name { get; set; }
public Virtual ICollection<Card> Cards { get; set; } = new List<Card>();
}
public class Card
{
public long CardId { get; set; }
public CardType Type { get; set; }
}
The entities would typically reflect all of the data in the underlying table, and the relationships between entities. The child collections are declared as virtual
to accommodate lazy loading if needed, and initialized as a new collection. This accommodates cases where we want to create a new entity and have it's child collection ready to go.
The DTOs represent just the data from the model that the consumer needs. This is where we also consider filtered views of data to suit the view. Rather than ICollection
, we can just use IEnumerable
. You can use ICollection
or IList
but IEnumerable
is generally the recommendation because it says to the consumer "here's a set of data you can read, but don't try adding to it, etc.".
public class BoardDTO
{
public int BoardId { get; set; }
public string Name { get; set; }
public IEnumerable<BoardListDTO> Lists { get; set; }
}
public class BoardListDTO
{
public int BoardListId { get; set; }
public string Name { get; set; }
public IEnumerabe<CardDTO> Cards { get; set; }
}
public class CardDTO
{
public long CardId { get; set; }
public CardType Type { get; set; }
}
In this example the DTOs look identical to the entities. Typically though, the entity and underlying tables will contain many fields, where our view models or DTOs only need a few fields, or relationships.
When it comes to populating your collection of DTOs for the view, you leverage projection using Select
. So if you want to list all boards that have at least 1 card of cardType 1, and then return those boards with only their CardType 1 cards:
This is assuming that CardType is mapped as an Enum. If CardType is mapped to a table, then it will need an entity / DTO as well.
var boards = context.Boards
.Where(b => b.Lists
.Any(bl => bl.Cards.Any(c => c.CardType == CardTypes.Type1)))
.Select(b => new BoardDTO
{
BoardId = b.BoardId,
Name = b.Name,
Lists = b.Lists.Select(bl => new BoardListDTO
{
BoardListId = bl.BoardListId,
Name = bl.Name,
Cards = bl.Cards.Where(c => c.CardType == CardTypes.Type1)
.Select(c => new CardDTO
{
CardId = c.CardId,
CardType = c.CardType
}).ToList()
}).ToList()
}).ToList()
This example does a lot of 1-to-1 mapping between entity and DTO. Often DTOs are flattened to represent a structure that the consuming view can use. This might consolidate the consumer model to just the Board and a list of cards with the board list name appearing within the related card DTO. (So a board DTO would just display a list of Cards that include their BoardList name.)
DTO/ViewModels like this are useful for filtering data because entities should always reflect the true data state so you cannot return entities with just a subset of some of the related cards. The Board will always associate with all board lists associated to it, and all cards associated to those. Using DTOs and Select
you can customize what data the view/consumer actually needs.
Source: stackoverflow.com
Related Query
- C# IQueryable - How to query a list inside another list
- How to make the Linq Query as efficient when select list inside the another select list
- How to set order of IQueryable query based on another list using linq in c#?
- How to use one Column of Sql query into another sql query inside C# Code
- Using Linq query inside List<T>.AddRange to conditionally add elements from one list to another
- linq - how do you do a query for items in one query source that are not in another one?
- How to use LINQ to query list of strings that do not contain substring entries from another list
- LINQ Filter List inside another LINQ Query
- How to filter linq query based on all of the values of one property from another list
- C# LINQ Find List Inside Another List, Better way to code this than a foreach loop
- How to add object to list (or other collection) that is inside another object?
- How to select list of objects inside another list of objects
- How to group a Data list inside a another list using linq?
- How to to perform Linq query of a list with another list
- How do I make my query return one another property inside dictionary
- How do I get all items in a list that are inside of another list?
- How do I get the objects from a list of objects which contain a duplicate property inside of another list in the object?
- How to use parameters from another list in a condition query
- How to get results from another query list if first linq query returns empty?
- Linq query to return items of list with another list inside it
- How to filter a List of objects inside another list
- How to construct a LINQ Query to test a list against another list where elements start with the elements from the other
- LINQ query to find if items in a list are contained in another list
- Using LINQ, select list of objects inside another list of objects
- How to filter a list based on another list using Linq?
- How do I move items from a list to another list in C#?
- How to find if an element of a list is in another list?
- How to query a nested list using a lambda expression
- In C#, how can I filter a list using a StartsWith() condition of another list?
- Linq - How to select items from a list that contains only items of another list?
More Query from same tag
- LINQ query optimization?
- Linq.Dynamic Select custom column with operation
- Explain the below Linq Query?
- Sort one list by another
- Reading XML file using Linq
- LINQ to Subsonic Left Outer Join
- Multiple filter Searching without having multiple options -ASP.NET MVC
- Sharepoint 2010 listitem to linq 2 sharepoint spmetal class
- NHibernate with LINQ (predicates?)
- self referential join using linq
- LINQ To Entities - M to M selection returns more columns than needed
- LINQ query - join and where clause not being obeyed?
- How to check string for null and assign its value in the same line
- Linq UNION query to select two elements
- Enumerable.OfType<>() not working as expected with route collection
- Is it possible to combine these 2 linq queries?
- How do you filter a list based on matching items in another list?
- LINQ with 2 WHERE condition
- how to format a date inside a collection of objects using linq in c#
- LINQ query return
- LINQ gives different results against XML and Db
- How to perform group by operation in dataTable using multiple columns dynamically in c#?
- linQ of selecting all rows of an excel file accepting null values
- Cartesian Product of Anonymous type
- Get list items by checking priority of another list using linq
- Complex DTO and LINQ
- Hierarchical grouping data using linq - remove recursion
- linq lambda expression for sql contains
- Entity Framework 6: Include nested nullable many to many children
- Linq, SQL, and ISNULL