ViewModels in Repository - c#

I have read that the repository layer should not deal with ViewModels because of separation of concerns and should instead deal only with Models. This is also true for the service layer (in my case this is where my business logic is). So then the controller is left to deal with the population of the ViewModels.
I have a Model Category:
public class Category
{
public int ID { get; set; }
public int? ParentCategoryID { get; set; }
public virtual ICollection<Product> Products{ get; set; }
public virtual ICollection<CategoryName> CategoryNames{ get; set; }
}
I have a ViewModel CategoryListViewModel used when displaying all Categories
public class CategoryListViewModel
{
public int ID { get; set; }
public string Name { get; set; }
public string ParentName { get; set; }
}
My view takes IEnumerable<...CategoryListViewModel>
This is how I populate the ViewModel from the controller:
public ActionResult Index()
{
IEnumerable<CategoryListViewModel> model;
List<CategoryListViewModel> list = new List<CategoryListViewModel>();
IEnumerable<Category> categoryList = categoryService.GetAllCategoriesList(RouteData);
foreach (var item in categoryList)
{
CategoryListViewModel temp = new CategoryListViewModel()
{
ID = item.ID,
Name = categoryService.GetCategoryName(RouteData, item.ID)
};
if (item.ParentCategoryID != null)
{
temp.ParentName = categoryService.GetCategoryName(RouteData, (int)item.ParentCategoryID);
}
list.Add(temp);
}
model = list;
return View(model);
}
My service methods:
public IEnumerable<Category> GetAllCategoriesList(RouteData data)
{
LanguageService languageService = new LanguageService();
Languages langEnum = languageService.LanguageStringToEnum(languageService.DetermineSelectedLanguage(data));
IEnumerable<Category> allCategories = repository.getAllCategoriesTest();
return allCategories;
}
public string GetCategoryName(RouteData data, int categoryId)
{
LanguageService languageService = new LanguageService();
Languages langEnum = languageService.LanguageStringToEnum(languageService.DetermineSelectedLanguage(data));
return repository.GetCategoryName(langEnum, categoryId);
}
And finally my repository methods:
public IEnumerable<Category> getAllCategoriesTest()
{
return db.Category.ToList();
}
public string GetCategoryName(Languages lang, int categoryId)
{
return db.CategoryName.Where(cn => cn.CategoryID == categoryId && cn.Language == lang).Select(cn => cn.Name).FirstOrDefault();
}
This approach looks very bad to me. My Controller is not thin anymore and I am running a lot of queries for something that simple.
If I allow ViewModels in my repository I get a much cleaner solution.
My Controller method:
public ActionResult Index()
{
return View(categoryService.GetAllCategories(RouteData));
}
Service method:
public IEnumerable<CategoryListViewModel> GetAllCategories(RouteData data)
{
LanguageService languageService = new LanguageService();
Languages langEnum = languageService.LanguageStringToEnum(languageService.DetermineSelectedLanguage(data));
return repository.SelectAllCategories(langEnum);
}
And repository method:
public IEnumerable<CategoryListViewModel> SelectAllCategories(Languages lang)
{
var categories = db.Category.Include(c => c.CategoryNames).Select(names => new CategoryListViewModel
{
ID = names.ID,
Name = names.CategoryNames.Where(cn => cn.Language == lang).Select(cn => cn.Name).FirstOrDefault(),
ParentName = db.CategoryName.Where(cn => cn.Language == lang && cn.CategoryID == names.ParentCategoryID)
.Select(cn => cn.Name).FirstOrDefault()
}).ToList();
return categories;
}
This approach, although violating separation of concerns seems to be "cleaner" to me.
My question is isn't the other approach more efficient in term of queries? Also is there any other way that this could be done so as not to write heavy controller methods and not execute that many queries? It seems to me that I am missing something.

First, bear in mind that even though it has "MVC" in the name, ASP.NET MVC only very loosely implements the MVC pattern. MVC tells you to have thin controllers because the Model is an active record, which handles all the business logic, including that around querying itself. This does not apply to ASP.NET MVC. There, your Model is actually a combination of your DAL, service layer, entity and one or more view models. This means the controller inevitably must do at least a little more work than a controller in something like Ruby on Rails, if only to wire all this stuff together.
As #Liam suggested in the comments above, your best bet is factories. That way, the controller does not actually own the logic for how to map an entity to a view model. You'll of course still need to actually call the factory in your controller, but the logic remains abstracted.
Also, a proper service layer should roll up logic that would otherwise be in your controller. If you need the localized name for the category, your service should have a method that returns all the categories with their localized name already. If you're having to hit your service multiple times, that's a clear indication that you haven't provided a necessary endpoint for your application. You may need to introduce a DTO to handle this data, since the entity class may not have the appropriate properties. You'd then have a factory that maps your DTO to a view model.
Finally, for what it's worth, your repository is completely unnecessary. Just have your service interact directly with your Entity Framework context. Having a repository buys you nothing but just an additional thing you have to maintain.

Related

Domain Model and related data (anemic domain model)

I'm currently working with ASP .NET Core 1.0 using Entity Framework Core. I have some complex calculations with data from the database and I'm not sure how to build a proper architecture using Dependency Injection without building an anemic domain model (http://www.martinfowler.com/bliki/AnemicDomainModel.html)
(Simplified) Example:
I have the following entities:
public class Project {
public int Id {get;set;}
public string Name {get;set;}
}
public class TimeEntry
{
public int Id {get;set;}
public DateTime Date {get;set;}
public int DurationMinutes {get;set;}
public int ProjectId {get;set;}
public Project Project {get;set;}
}
public class Employee {
public int Id {get;set;}
public string Name {get;set;}
public List<TimeEntry> TimeEntries {get;set;}
}
I want to do some complex calculations to calculate a monthly TimeSheet. Because I can not access the database within the Employee entity I calculate the TimeSheet in a EmployeeService.
public class EmployeeService {
private DbContext _db;
public EmployeeService(DbContext db) {
_db = db;
}
public List<CalculatedMonth> GetMonthlyTimeSheet(int employeeId) {
var employee = _db.Employee.Include(x=>x.TimeEntry).ThenInclude(x=>x.Project).Single();
var result = new List<CalculatedMonth>();
//complex calculation using TimeEntries etc here
return result;
}
}
If I want to get the TimeSheet I need to inject the EmployeeService and call GetMonthlyTimeSheet.
So - I end up with a lot of GetThis() and GetThat() methods inside my service although this methods would perfectly fit into the Employee class itself.
What I want to achieve is something like:
public class Employee {
public int Id {get;set;}
public string Name {get;set;}
public List<TimeEntry> TimeEntries {get;set;}
public List<CalculatedMonth> GetMonthlyTimeSheet() {
var result = new List<CalculatedMonth>();
//complex calculation using TimeEntries etc here
return result;
}
}
public IActionResult GetTimeSheets(int employeeId) {
var employee = _employeeRepository.Get(employeeId);
return employee.GetTimeSheets();
}
...but for that I need to make sure that the list of TimeEntries is populated from the database (EF Core does not support lazy loading). I do not want to .Include(x=>y) everything on every request because sometimes I just need the employee's name without the timeentries and it would affect the performance of the application.
Can anyone point me in a direction how to architect this properly?
Edit:
One possibility (from the comments of the first answer) would be:
public class Employee {
public int Id {get;set;}
public string Name {get;set;}
public List<TimeEntry> TimeEntries {get;set;}
public List<CalculatedMonth> GetMonthlyTimeSheet() {
if (TimeEntries == null)
throw new PleaseIncludePropertyException(nameof(TimeEntries));
var result = new List<CalculatedMonth>();
//complex calculation using TimeEntries etc here
return result;
}
}
public class EmployeeService {
private DbContext _db;
public EmployeeService(DbContext db) {
_db = db;
}
public Employee GetEmployeeWithoutData(int employeeId) {
return _db.Employee.Single();
}
public Employee GetEmployeeWithData(int employeeId) {
return _db.Employee.Include(x=>x.TimeEntry).ThenInclude(x=>x.Project).Single();
}
}
public IActionResult GetTimeSheets(int employeeId) {
var employee = _employeeService.GetEmployeeWithData(employeeId);
return employee.GetTimeSheets();
}
Do not try to solve querying problems with your aggregates. Your aggregates are meant to process commands and protect invariants. They form a consistency boundary around a set of data.
Is the Employee object responsible for protecting the integrity of an employee's timesheet? If it doesn't then this data doesn't belong into the Employee class.
Lazy-loading may be fine for CRUD models, but is usually considered an anti-pattern when we design aggregates because those should be as small and cohesive as possible.
Are you taking business decisions based on the calculated result from timesheets? Is there any invariants to protect? Does it matter if the decision was made on stale timesheet data? If the answer to these questions is no then your calculation is really nothing more than a query.
Placing queries in service objects is fine. These service objects may even live outside the domain model (e.g. in the application layer), but there is no strict rule to follow. Also, you may choose to load a few aggregates in order to access the required data to process the calculations, but it's usually better to go directly in the database. This allows a better separation between your reads & writes (CQRS).
If I understood your question correctly you can use a trick with injecting a service into your entities that helps it do the job, e.g.:
public class Employee()
{
public object GetTimeSheets(ICalculatorHelper helper)
{
}
}
Then in your service that holds the employees you would obtain it in the constructor and pass to the employee class for calculations. This service can be a Facade e.g. for getting all the data and perform initialization or whatever you really need.
As for the TimeEntries, you can get them using a function like this:
private GetTimeEntries(ICalculationHelper helper)
{
if (_entries == null)
{
_entries = helper.GetTimeEntries();
}
return _entries;
}
It depends of course on you strategy of caching and so on if this pattern fits you.
Personally I find it rather easy to work with anemic classes and have a lot of the business logic in services. I do put some in the objects, like e.g. calculating FullName out of FirstName and LastName. Usually stuff that does not involve other services. Though it's a matter of preference.

MVC Design query on Controller/Models

A few queries on EF.
Questions -
Should the methods that directly use database context object be part of Controller classes or Models?
ContactManagerContext.cs (which I am considering as a DAL layer?) Is my assumption correct?
Where should the ContactManager class be placed? Model or DAL? It is currently part of the Model class.
will add more questions
This is how I have structured the classes - Models and Controllers.
Please review and comment on if the code is structured correctly or not and how it can be improved.
Model class (Contact.cs):
using Contact_Manager.DAL;
namespace Contact_Manager.Models
{
public class Contact
{
[Key]
public int ContactId { get; set; }
[Required, MaxLength(100)]
public string FirstName { get; set; }
[Required, MaxLength(100)]
public string LastName { get; set; }
public string EMail { get; set; }
public string Phone { get; set; }
public string BusinessName { get; set; }
}
public class ContactManager
{
ContactContext db = new ContactContext();
public IEnumerable<Contact> ContactList(int? selectedContact)
{
IQueryable<Contact> contacts = db.Contacts;
return contacts.ToList();
}
}
}
ContactManagerContext.cs (DAL)
------------------------------
using System.Data.Entity;
using System.Linq;
using Contact_Manager.Models;
namespace Contact_Manager.DAL
{
public class ContactContext : DbContext
{
public ContactContext()
: base("ContactMgrDBContext")
{
Database.SetInitializer<ContactContext>(new DropCreateDatabaseIfModelChanges<ContactContext>());
}
public DbSet<Contact> Contacts { get; set; }
}
}
ContactController.cs (Controller class):
using System.Web.Mvc;
using System.Linq;
using Contact_Manager.Models;
namespace Contact_Manager.Controllers
{
public class ContactController : Controller
{
//
// GET: /Contact/
public JsonResult ContactList()
{
ContactManager cMgr = new ContactManager();
IEnumerable<Contact> contactList = cMgr.ContactList(0);
//var contactsJson = JsonConvert.SerializeObject(contacts.ToList());
return Json(contactList, JsonRequestBehavior.AllowGet);
}
public ActionResult Index()
{
return View();
}
}
}
The MVC pattern is one of the most misunderstood architecture patterns.
Also if it is used very often in UI it is a more general approach. The common usage has to be separated from the aim to adress different responsibilities.
The best way to explain MVC is to see it as a pattern that separates responsibilities AND the collaboration between them in ONE layer. So you may have MVC in the UI-Layer, but also in the DAO-Layer.
For example in the UI-Layer a model object is an object that holds the state of a UI-Component. The View-Object is the UI-Component that holds logic to draw itself on base of the model object state. The Controller retreives events from different sources and orchestrates communication between model and view.
In the DAO-Layer the model object is a part of a database state (often a row). Think of an ORM-Object. The view object is the representation for the "next" layer. The controller is the DAO that orchestrates mappings and changes.
In general you need something that holds a STATE (model). Then you need an external representaion of the STATE to PUBLISH (view) avoiding coupling to the STATE. After all you have to have BEHAVIOUR (controller) orchestrate changes and mappings.
The approach to see MVC as layers may work for small projects. In larger projects you will face problems in maintainability because you have definitely MORE than three responsibilities. And if you only have three layers you will mix responsibilities lacking the Single Responsibility Principle.
To answer your questions:
No. Write a separate DAO for that. The controller and/or the model should use that.
No. See 1.
If we talk about MVC the controller is the controller. Nothing else. If we talk about layers the controller seems to mix responsibilities of UI, Model maybe DAO. So the assignment is ambiguous.
You can you the three Layers' model in the Controller part. the Controller will be the highest layer, and it will "talk" with the BL and so on.
The Models suppose to be simple and clean.

How many GET methods a service should have?

What are the best practices for writing a service layer methods that retrieves data from repository?
Let's say we have two models: Team and User (user is part of a team):
public class User {
public int Id { get; set; }
public string Name { get; set; }
public int TeamId { get; set; }
public virtual Team Team { get; set; }
public bool Active { get; set; }
}
public class Team {
public int Id { get; set; }
public string Name { get; set; }
public bool Active { get; set; }
}
If I want to write service to retrieve user data from repository by various conditions, do I have to write multiple methods to get a user e.g. getAll, getAllByName, getAllActiveByName, getAllActiveByTeamId, getAllActiveByNameAndTeamId, etc?
public IEnumerable<User> GetAll()
{
return _repository.GetAll();
}
public IEnumerable<User> GetAllActiveByName(string name)
{
return _repository.GetBy(u => u.Name == name && u.Active);
}
public IEnumerable<User> GetAllActiveByNameAndTeamId(string name, int teamId)
{
return _repository.GetBy(u => u.Name == name && u.Active && u.TeamId == teamId);
}
These are just simple examples but in real life we can end up having tens of service methods for different scenarios, when models are more complex.
Or maybe it is better to have one GetBy method that will return users based on the provided filter? I use Generic Repository Pattern and I could use GetBy method when implementing GetBy service method:
public IEnumerable<User> GetBy(Expression<Func<User, object>>filter )
{
return _usersRepository.GetBy(filter);
}
Having this I would not have to write tens of "duplicated" methods for all the scenarios.
Then it would be controller responsibility to set the filter:
public ViewResult Index(int teamId = 0){
//[...]
var users = _usersService.GetBy(u => u.IsActive && u.teamId == teamId);
//[...]
}
Any thoughts on that?
I'm of the opinion that you should have as many query methods as you have scenarios.
In that way you can optimize individual queries by for example using a precalculated view.
Some of your queries might use eager loading, other might use lazy loading...
Also, if you always return IQueryable how are you going to test it? Your service will have only one method GetAll and is so anemic that you can just get rid of it and use repository directly in the controller.
Another argument against GetAll is that any one can execute any query in the UI!
Consider reading about CQRS.
Or maybe it is better to have one getAll method that will return only
active users and then use lambda expression in the controller?
No. This kind of query will be good only for static data that too in-memory. Say you have some application level data and it is not going to change for certain time, then instead of querying it everytime, you getall for first time and then put in local server cache. Then use it for next simultaneous requests. But this approach is not going to for heavily changing dynamic data. Also performance of this query depends on number of records it is returning, so sometimes it might give very bad performance.
do I have to write multiple methods to get a user e.g. getAll,
getAllByName, getAllActiveByName, getAllActiveByTeamId,
getAllActiveByNameAndTeamId, etc?
Thats better. This approach will give you load on demand freedom, that means load necessary data when it is required, instead of getting all data and discarding it.

How to combine MVC4 with EF5 Db First separate project

In my solution I have two projects. One is the main MVC4 project. The other is a DataLayer project which contains an Entity Framework 5 edmx model generated from an existing DB (and maybe some Repositories later).
The problem is that the pocos EF5 generates sits in the DataLayer project. But I need them inside the Models folder in the MVC4 project.
I want the seperate DataLayer project to increase abstraction and separation of concerns, but I can't figure out how to put those two pieces together.
(I thought to maintain another layer of pocos in the Models folder but this dose not seems right)
I have my projects separated into two as you describe.
I thought to maintain another layer of pocos in the Models folder but this dose not seems right
I think you will find you will build this layer eventually.
Here's two projects Project.Data and Project.Web. Project.Web has a project reference to Project.Data.
Project.Data.Models: Entities
Project.Web.Models: DTOs, ViewModels
My views never directly reference Entities. I will map Entities to DTOs or ViewModels using AutoMapper. This happens in my services which sits in Project.Web under its own namespace. My services never return Entity types and my views use only ViewModels.
interface IFooService
{
FooDTO GetFoo(int id);
}
public class FooService : IFooService
{
public FooDTO GetFoo(int id)
{
var foo = dbContext.Foo.Where(f => f.Id == id).Select(f => new FooDTO {
Bar = f.Bar,
Blah = f.Blah
}).FirstOrDefault();
// I let AutoMapper take care of the mapping for me
var foo = Mapper.Map<FooDTO>(dbContext.Foo.Where(f => f.Id == id).FirstOrDefault());
return foo;
}
}
Controller Action:
public ActionResult FooDetails(int id)
{
FooViewModel foo = Mapper.Map<FooViewModel>(fooService.GetFoo(id));
return View(foo);
}
Edit:
Added anther model layer to map Entity => DTO => View Model
This is the job of the repository. Create DTO classes to hold view friendly models and use the repository to call your data layer and assemble the dto. The dtos can then be built specifically for being returned to the client, including any serialization or display decorations, etc. Nothing complicated here.
I think some people's first reaction is "I'm duplicating my effort if I have to create these classes" but you're really not as these classes serve a different purpose which is exactly what you're saying, separation of concerns.
public MyViewModel // model that is bound to the view
{
private UserRepository _userRepo;
public EmployeeDto ActiveUser {get;set;}
public MyViewModel()
{
_userRepo = new UserRepository();
LoadActiveUser();
}
private void LoadActiveUser()
{
var userId = (int)HttpContext.Current.Session["activeUser"] ?? 0;
if(userId > 0)
{
ActiveUser = _userRepo.GetEmployee(userId);
}
}
}
public UserRepository
{
private SomeEntityReference1 _myDal1;
private SomeEntityReference2 _myDal2; // maybe you need to make some other data layer call in order to fill this object out
public UserRepository()
{
_myDal1 = new SomeEntityReference1 ();
_myDal2 = new SomeEntityReference2 ();
}
public EmployeeDto GetEmployee(int id)
{
var empDto = new EmployeeDto();
// get employee
var dalEmpResult = _myDal.Employees.FirstOrDefault(e => e.EmployeeId == id);
empDto.FirstName = dalResult.FName;
empDto.LastName = dalResult.LName;
empDto.Id = dalResult.EmployeeId;
// get employee department info
var dalDeptResult = _myDal2.Departments.FirstOrDefault(d => e.DepartmentId == dalEmpResult.DeptartmentId);
empDto.DepartmentName = dalDeptResult.Name;
return empDto;
}
}
// client friendly employee object
[DataContract(Name="Employee")]
public class EmployeeDto
{
public int Id {get; internal set;}
[DataMember(Name="fname")]
[DisplayName("Employee First Name:")]
public string FirstName {get;set;}
[DataMember(Name="lname")]
[DisplayName("Employee Last Name:")]
public string LastName {get;set;}
public int DeptId {get;set;}
[DataMember(Name="dept")]
[DisplayName("Works at:")]
public string DepartmentName {get;set;}
}
The only reason I show two different EF references here (your database entity schemas) is just to illustrate that this would be your opportunity to do any "additional" processing before returning a FINISHED dto, ready for consumption.

How to Validate Business Rule in Service or Repo

I am hoping to create a base Entity Class that includes a validation rule that checks if a field called "Title" is unique (which of course requires a db scan). I want the inherited models to run the validation rule in the repo (or service) layer and send a ValidationResult to the (MVC) client-layer.
The problem is one of inheritance.
public interface IUniqueTitle
{
int Id { get; set; }
string Title { get; set; }
// This is a "multi-client, one database" solution.
// Data is isolated using SiteId
int SiteId { get; set; }
}
// Models such as "MemberClub" and "Assessment" will inherit from this
public class EntityUniqueTitle : IUniqueTitle
{
public int Id { get; set; }
public int SiteId { get; set; }
public string Title { get; set; }
}
// This class will be used in production
public class MemberClub : EntityUniqueTitle
{
}
I wrote an extension method that to check to see if the Title field is unique based on the SiteId
public static bool IsUniqueTitle<T>(this IQueryable<T> items, T currentEntity) where T : IUniqueTitle
{
return items.Where(
item => item.Id != currentEntity.Id // INCASE UPDATING OBJECT
& item.SiteId == currentEntity.SiteId
& item.Title == currentEntity.Title)
.Count() == 0;
}
Here is where I get stuck. Where should I put the validation?
I can put in the Repo but can't figure out how to fire the ValidationResult upon Save
public class RepoUniqueTitle<T> : IRepoUniqueTitle<T> where T : EntityUniqueTitle, new()
{
protected readonly DbContext c;
public Repo(IDbContextFactory f) { c = f.GetContext(); }
public void Insert(T o)
{
if (!c.Set<T>().IsUniqueTitle(o))
{
// ***********************
// PROBLEM HERE, HOW DO I STOP AND SEND A VALIDATIONRESULT TO THE CLIENT?
// IF POSSIBLE, AUOTMATIC WHEN MODEL.ISVALID IS CALLED
// code from base repo class for reference
// if (o is IUniqueTitleForSite)
// IoC.Resolve<IRepoUniqueTitle<T>>().Validate(o);
}
else
c.Set<T>().Add(o);
}
}
I am hoping there is a validation solution that:
Models can inherit from a base Entity
Can make db calls to the inherited entity's collection
Works with ValidationResult so it can be cleanly integrated into MVC Tier
Called during Model.isValid if possible
Note: I am using ProDinner as a basis for an "n-tier code-first EF mvc/wf" solution.
Sorry, a lot of this is new to me. Any help you can provide would be greatly appreciated!
If you have separate business logic layer you should place the validation to that layer. Otherwise why to have that layer if you don't use it to execute business rules?
Anyway unique check is tricky because there is a delay between your query and actual saving of data and another thread can insert the item with the same title during that delay. You should place unique index on Title and SiteId to enforce uniqueness in the database. In such case former problem will result in the exception which you must handle somehow but it is probably better then data duplicity.

Categories

Resources