Single query object support in the repository

We have seen how a list of objects was returned from the repository in a generic fashion. Let's have a provision to return a single object from the repository:

    public interface IPostRepositoryWithQueries
{
// Code removed for brevity
Post GetSingle<T>(T query) where T : class;
Task<Post> GetSingleAsync<T>(T query) where T : class;
}

The preceding code adds synchronous and asynchronous methods to return a single Post object from the repository, still retaining the generic implementation since it could be used by multiple query objects that might return individual Post objects:

    public class GetPostByIdQuery
{
public GetPostByIdQuery(int? id, bool includeData)
{
this.Id = id;
this.IncludeData = includeData;
}

public int? Id { get; set; }
public bool IncludeData { get; set; }
}

The query type we have created now has one more filter by Id, apart from retaining IncludeData from the previous query type. The handler interface required to return single Post type is defined below:

    public interface IPostQuerySingleHandler<T> where T : class
{
Post Handle(T query);
Task<Post> HandleAsync(T query);
}

We have a corresponding generic query handler to handle a single object from the handler implementation, which has synchronous and asynchronous support as well.  The following code provides concrete implementation required for the GetPostByIdQueryHandler to filter Posts by identifier:

    public class GetPostByIdQueryHandler :
IPostQuerySingleHandler<GetPostByIdQuery>
{
private readonly BlogContext _context;

public GetPostByIdQueryHandler(BlogContext context)
{
this._context = context;
}

public Post Handle(GetPostByIdQuery query)
{
return query.IncludeData
? _context.Posts.Include(p => p.Author)
.Include(p => p.Blog)
.Include(p => p.Category).SingleOrDefault(x =>
x.Id.Equals(query.Id))
: _context.Posts
.SingleOrDefault(x => x.Id.Equals(query.Id));
}

public async Task<Post> HandleAsync(GetPostByIdQuery query)
{
return query.IncludeData
? await _context.Posts.Include(p => p.Author)
.Include(p => p.Blog)
.Include(p => p.Category).SingleOrDefaultAsync(x =>
x.Id.Equals(query.Id))
: await _context.Posts
.SingleOrDefaultAsync(x => x.Id.Equals(query.Id));
}
}

The query handler now ports the filter by id implementation to the handler; additionally, it includes/excludes related data based on the IncludeData filter:

    public class PostRepositoryWithQueries :
IPostRepositoryWithQueries
{
private readonly BlogContext _context;

public PostRepositoryWithQueries(BlogContext context)
{
_context = context;
}

public Post GetSingle<T>(BlogContext context, T query)
where T : class
{
//switch (typeof(T).Name)
//{
// case "GetPostByIdQuery":
// var getPostByIdQueryHandler = new
GetPostByIdQueryHandler(context);
// return getPostByIdQueryHandler.Handle(query as
GetPostByIdQuery);
//}

var getPostByIdQueryHandler = new
GetPostByIdQueryHandler(context);
return getPostByIdQueryHandler.Handle(query
as GetPostByIdQuery);
}

public async Task<Post> GetSingleAsync<T>(BlogContext
context, T query)
where T : class
{
//switch (typeof(T).Name)
//{
// case "GetPostByIdQuery":
// var getPostByIdQueryHandler =
new GetPostByIdQueryHandler(context);
// return await getPostByIdQueryHandler.HandleAsync(query
as GetPostByIdQuery);
//}

var getPostByIdQueryHandler =
new GetPostByIdQueryHandler(context);
return await getPostByIdQueryHandler.HandleAsync(query
as GetPostByIdQuery);
}
}

We have commented code in the repository implementations since, currently, it supports only one query handler for returning a single object and having a switch case doesn't make any sense. Once we start adding new implementations for handling single objects, we will be using commented code instead, which supports multiple queries through a single action:

    public class PostsController : Controller
{
// Code removed for brevity

// GET: Posts/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}

var post = await _repositoryWithQueries.GetSingleAsync(_context,
new GetPostByIdQuery(id, true));

if (post == null)
{
return NotFound();
}

return View(post);
}

// GET: Posts/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}

var post = await _repositoryWithQueries.GetSingleAsync(_context,
new GetPostByIdQuery(id, false));


// Code removed for brevity
}
}

In the controller code, it is obvious that GetSingleAsync is used in multiple actions, but in the preceding highlighted usages one was including related data and the other was excluding it. We can also see the following code which provides the Delete action implementation along with include related data as it will be rendered in the Delete confirmation screen:

    // GET: Posts/Delete/5
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}

var post = await _repositoryWithQueries.GetSingleAsync(_context,
new GetPostByIdQuery(id, true));

if (post == null)
{
return NotFound();
}

return View(post);
}

We have explored how query objects need to be incorporated inside the repository and implemented this for one single and list operation. Let's again take the remaining implementations as an assignment and complete the repository incorporation.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset