ICRUDRepository interface

namespace: MvcControlsToolkit.Core.Business.Utilities

The ICRUDRepository interface is the standard way Base controllers interact with the business layer. You may use either its default implementation, or classes inheriting from the default implementation, or completely custom implementations.

It contains all CRUD operations, paged retrieval operations, single record retrieval, and methods for copying back newly created principal keys in the associated ViewModels/DTO:

public interface ICRUDRepository
{
    void Update<T>(bool full, params T[] viewModel);
    void UpdateList<T>(bool full, IEnumerable<T> oldValues, IEnumerable<T> newValues);
    void Add<T>(bool full, params T[] viewModel);
    void Delete<U>(params U[] key);
 
    Task<T> GetById<TU>(U key);
 
    Task<DataPage<T>> GetPage<T>(Expression<Func<Tbool>> filter,
        Func<IQueryable<T>, IOrderedQueryable<T>> sorting,
        int page, int itemsPerPage, Func<IQueryable<T>, IQueryable<T>> grouping=null);
 
    Task<DataPage<T1>> GetPageExtended<T1T2>(Expression<Func<T1bool>> filter,
        Func<IQueryable<T2>, IOrderedQueryable<T2>> sorting,
        int page, int itemsPerPage, Func<IQueryable<T1>, IQueryable<T2>> grouping = null)
        where T2T1;
 
    Task SaveChanges();
    void UpdateKeys();
 
    Func<objectobject> GetKey { get; }
        
}

In all methods containing bool full, full set to true declares that all viewModels/DTO contain all fields of the corresponding DB class, so there is no need to retrieve the original DB object to apply modifications, but it is enough to attach a new instance of the DB class to its DBSet, then copying all ViewModels/DTO properties, and finally setting the DB object state to modified.

All methods operate with ViewModels/DTO objects in such a way to hide the DB classes to the UI layer. Important: ViewModel key type may correspond either to the same DB model type or to a possible nullable version of it.

The meaning of Update, Add, and deletes is obvious. GetById retrieve a single instance given its key. SaveChanges save changes to the database and, if needed, copy newly created keys back into the corresponding ViewModels. UpdateKeys performs just the newly created keys copy operation and is used typically when changes to the DB context are saved by another repository. GetKey is for internal use, and custom ICRUDRepository implementations should simply return null.

The UpdateList<U> accepts two lists of ViewModels: the original list before some CRUD modifications are applied by the user, and the version of the same list after all user modifications. It uses these two lists to autodetect all Add, Update and Deletes performed by the user and applies all of them to the DBSet. Typically, the unmodified version of the list is obtained by storing the original list in the Razor View with the help of the store-model TagHelper.

GetPage returns a page of data given the page number, the items per page, a filter to apply (expressed in terms of ViewModel properties), chain of sorting operators and an optional grouping.
The second overload allow a different ViewModel for grouped data. Use it only if the grouping function is not null.

await Repository.GetPage<ProductViewModel>(
        null,
        q => q.OrderBy(m => m.Name),
        currPage, 3)
                

The DataPage<T;> class is defined as:

            
    public class DataPage<T>
    {
        public ICollection<T> Data { get; set; }
        public int Page { get; set; }
        public int TotalPages { get; set; }
        public int TotalCount { get; set; }
        public int ItemsPerPage { get; set; }
    }
        
        

TotalCount contains the total number of items that satisfy the query, while TotalPages contains the total number of data pages. Data contains the actual data composing the page.

The example below show how to use the two overloads of GetPage when receivig OData queries in the url:

var query = queryProvider.Parse<FoodViewModel>();
 
int pg = (int)query.Page;
var grouping = query.GetGrouping<FoodViewModelGrouping>();
 
var model = new FoodListViewModel
{
    Query = query,
    Products =
        grouping == null ?
            await Repository.GetPage(
                query.GetFilterExpression(),
                query.GetSorting() ??
                    (q => q.OrderBy(m => m.ProductName)),
                pg, 5)
            :
            await Repository.GetPageExtended(
                query.GetFilterExpression(),
                query.GetSorting<FoodViewModelGrouping>() ??
                    (q => q.OrderBy(m => m.ProductName)),
                pg, 5,
                query.GetGrouping<FoodViewModelGrouping>())


Fork me on GitHub