Skip to content
Jon P Smith edited this page Jan 24, 2019 · 6 revisions

CrudServices has tow types of Read method, which are used in very different ways.

  • The ReadSingle<T> versions are used in detailed display, and the initial stages of update and delete
  • The ReadManyNoTracked<T> is use when you want to produce a list.
  • The ProjectFromEntityToDto<TEntity,TDto>(preDtoLinqQuery) allows you to alter the query before the DTO mapping. I will cover each one separately.

NOTE: In version 2.0.0 and above the Read methods support DbQuery types.

ReadSingle<T>

There are two versions of this command, both of which can handle a entity class or a GenericServices' DTO (with its ILinkToEntity<TEntity> interface). They are:

  • ReadSingle<T>(params object[] keys), which uses the primary key value(s) to load the item.
  • ReadSingle<T>(Expression<Func<T, bool>> whereExpression), which uses a LINQ expression to find an single instance.

Both of these return a status error saying "Sorry, I could not find the {class name or description} you were looking for" if no entry was found. The whereExpression version will throw an exception if more than one instance is found.

If you ask for an entity class then will return a tracked entity, i.e. you can alter the instance returned and call EF Core's SaveChanges method to update that entity.

Typically in web/mobile applications the is ReadSingle<T> methods are used to show the user a page that contains, which is why they support projection to a DTO. The DTO can contain.

  1. Read-only information - used for the user to confirm that this is the correct item to update/delete.
  2. Read/Write information - these are the inputs for the user to edit/change things in an update.

In the document GenericServics and DTOs I talk about how the Read-only information should be marked with the [ReadOnly(true)] attribute. Its important to do that.

NOTE: When building update pages in a web application you should always return the Read-Only values (most like via hidden inputs) in case there is an error. Otherwise, when you redisplay the page some of the information will be missing. See all the update RazorPageApp examples, where I do that.

ReadManyNoTracked<T>()

This is the method you will use to list things. It returns an IQueryable<T>, which you can then filter, page etc. - see Home/Index/Index.cshtml.cs for a implementation that adds sorting, filtering and paging on the result of a ReadManyNoTracked<BookListDto>() call. As the name says - its not tracked, so its read-only.

If you provide ReadManyNoTracked<T>() with a GenericServices DTO it will use AutoMapper to create a LINQ Select query.

ProjectFromEntityToDto<TEntity,TDto>(preDtoLinqQuery)

This method allows you to add a LINQ query on the entity type, i.e. before the mapping of the entity to a DTO. This allows you to do two things that the other methods don't allow.

  • You can filter on properties that aren't in the DTO version.
  • You can apply the method .IgnoreQueryFilters() to the entity to turn off any Query Filter on the entity before mapping to a DTO. This is useful when you are using Query Filters for soft delete.

Here is an example

public class BookTitleOnlyDto : ILinkToEntity<Book>
{
    public string Title { get; set; }
}

//... code in your action/razor page etc.

var dto = service.ProjectFromEntityToDto<Book,BookTitleOnlyDto>(
    x => x.Where(y => y.BookId == 1)).Single();

Note about DTO mapping for all read methods

When reading to a DTO sometimes the default AutoMapper mapping may not do produce the LINQ you want. In that case you need to add a PerDtoConfig<TDto,TEntity> class, where you can alter the read mapping. See this link on how to do that.