I need to create an administration interface in MVC, over an old and seriously crappy DB. The fields and tables have no consistency whatsoever, but that’s easily solved through renaming things with Entity Framework. But now, I need to do 5 administration interfaces for 5 trios of tables : “master”, “images” and “categories”. They are pretty much the same, except the table and field names. To do that, let’s play with abstraction.
I’m using crude ViewModels to display my search pages. They get the elements to display in the search dropdown lists, and paginate the results. All of the logic is in the constructor (the viewmodel is only used to display a search screen). When the constructor needs to get specific elements, it calls abstract methods. They are the ones that are actually different in the various pages.
The abstract base looks like this :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
using MvcPaging; public abstract class BaseElementListViewModel { public BaseElementListViewModel(int? page, int? category, int? format, int? status) { this.Statuses = this.GetStatuses(status); this.Categories = this.GetCategories(category); this.Formats = this.GetFormats(format); using (var db = new SoftwareAdminEntities()) { var baseQuery = this.GetBaseQuery(db); // filter the baseQuery with the selected category, format and status this.Results = baseQuery.ToPagedList(this.PageNumber, this.PageSize, this.TotalNumber); } } public IEnumerable<SelectListItem> Categories { get; set; } public IEnumerable<SelectListItem> Formats { get; set; } public IPagedList<IElementCombination> Results { get; set; } public IEnumerable<SelectListItem> Statuses { get; set; } protected abstract IQueryable<IElementCombination> GetBaseQuery(ModelEntities db); protected abstract IEnumerable<SelectListItem> GetCategories(int? category); protected abstract IEnumerable<SelectListItem> GetFormats(int? format); private IEnumerable<SelectListItem> GetStatuses(int? currentStatus) { // gets the list of statuses ; they are always the same for all elements } } |
And now the implementation is very simple ; here for the themes :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
public class ThemesListViewModel : BaseElementListViewModel { public ThemesListViewModel(int? page, int? category, int? format, int? status) : base(page, category, format, status) { } protected override IQueryable<IElementCombination> GetBaseQuery(SoftwareAdminEntities db) { return from i in db.Theme_Images join m in db.Theme_Master on i.ThemeMasterID equals m.ThemeMasterID orderby i.CreatedDate descending select new Theme_Combination { Active = i.Active, AllowInterior = i.AllowInterior, ImageID = i.BackgroundImageID, BookSizeID = m.BookSizeID, Checksum = i.Checksum, Created = i.CreatedDate, FileType = i.File_type, Modified = m.ModifiedDate, Size = i.Size, Sort = i.Sort, Status = i.Status, CategoryID = m.ThemeCategoryID, MasterID = m.ThemeMasterID, Version = m.Version }; } protected override IEnumerable<SelectListItem> GetCategories(int? category) { // get the list of categories } protected override IEnumerable<SelectListItem> GetFormats(int? format) { // get the list of formats } } |
Theme_Combination is the joining of two entities, Master and Images. All your element_combination must inherit from IElementCombination. If they do not implement anything specific themselves, you can even use a single ElementCombination class.