I've come up with a design pattern that's a mix of other patterns like Mediator, Repository, Factory.
The idea is that instead of passing a specific object like a UserViewModel from the UI to the BL the UserViewModel is wrapped in a transaction object. By doing this the UserViewModel becomes a property of the wrapper class along with other info like number of records, a user id for auditing, a response status etc;
Will this be maintainable for a DB that has 100+ entities?
This is some bare-bones sample code:
class Program
{
static void Main(string[] args)
{
string loggedInUserId = "55541";
IBaseService baseService = new BaseService();
var requestModel1 = new SystemTransactionModel<IEnumerable<UserViewModel>>(loggedInUserId);
var responseModel = baseService.GetObjects(requestModel1, a => a.USER_ID == "65412");
if (responseModel.Successful)
{
Console.WriteLine("USERS");
foreach (var item in responseModel.ResponseObject)
Console.WriteLine($"{item.UserId} - {item.FirstName}");
}
var requestModel2 = new SystemTransactionModel<IEnumerable<RolesViewModel>>(loggedInUserId);
var responseModel2 = baseService.GetObjects(requestModel2, a => a.ROLE_ID == "1002");
if (responseModel2.Successful)
{
Console.WriteLine("ROLES");
foreach (var item in responseModel2.ResponseObject)
Console.WriteLine(item.RoleName);
}
}
}
Business Logic
public interface IBaseService : IBaseFactory<SYS_USERS, UserViewModel>,IBaseFactory<SYS_ROLES, RolesViewModel>,
{
//place any one-off items here
}
//base component that manages requests from the UI to the BL
public partial class BaseService : IBaseService
{
//get some data from the DB
//EntityModel = SYS_USERS
//ViewModel = UserViewModel
public SystemTransactionModel<IEnumerable<UserViewModel>> GetObjects(SystemTransactionModel<IEnumerable<UserViewModel>> requestModel, Expression<Func<SYS_USERS, bool>> query) => new BaseFactory<SYS_USERS, UserViewModel>().GetObjects(requestModel, query);
public SystemTransactionModel<IEnumerable<RolesViewModel>> GetObjects(SystemTransactionModel<IEnumerable<RolesViewModel>> requestModel, Expression<Func<SYS_ROLES, bool>> query) => new BaseFactory<SYS_ROLES, RolesViewModel>().GetObjects(requestModel, query);
}
Service Factory
public interface IBaseFactory<TEntity, TModel>
{
SystemTransactionModel<IEnumerable<TModel>> GetObjects(SystemTransactionModel<IEnumerable<TModel>> requestModel, Expression<Func<TEntity, bool>> query = null);
}
//generic factory that manages transactions between ViewModes and EntityModels
public class BaseFactory<TEntity, TModel> : IBaseFactory<TEntity, TModel> where TEntity : class
{
public SystemTransactionModel<IEnumerable<TModel>> GetObjects(SystemTransactionModel<IEnumerable<TModel>> transactionModel, Expression<Func<TEntity, bool>> query)
{
//data from db context
//Repository/UnitOfWork
IQueryable<TEntity> source = context<TEntity>().Where(query);
//AutoMapper map the data results into an view model
var destination = iMapper.Map<IQueryable<TEntity>, List<TModel>>(source).AsEnumerable();
if (destination != null)
{
transactionModel.ResponseObject = destination;
transactionModel.Successful = true;
}
return transactionModel;
}
}
Transaction wrapper
//this class is the object that is sent to and from the UI (ASP.NET MVC) and the backend (Services that manage the any custom BL and mapping between ViewModels and EntityModels)
public class SystemTransactionModel<T>
{
//example of an auditing paramater
//to track who sent the request
public string UserId {get;set;}
public bool Successful { get; set; } = false;
public T ResponseObject { get; set; }
public SystemTransactionModel(string userId){
UserId = userId;
}
}
View/Entity Models
//ViewModels
public class UserViewModel
{
public string LastName { get; set; }
public string FirstName { get; set; }
public string UserId { get; set; }
}
public class RolesViewModel
{
public string RoleId { get; set; }
public string RoleName { get; set; }
}
//Entity Models
public class SYS_USERS
{
public string USER_ID { get; set; }
public string USER_FIRST_NAME_MI { get; set; }
public string USER_LAST_NAME { get; set; }
}
public class SYS_ROLES
{
public string ROLE_ID { get; set; }
public string ROLE_NAME { get; set; }
}
Aucun commentaire:
Enregistrer un commentaire