Domain Model and related data (anemic domain model) - c#

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.

Related

C# Repository Pattern? Complex queries still placed inside repository?

I am learning the Repository Pattern. I have managed to write the code to do it.
I read the article say each Repository related to one entities.
This is what i have for my Repository:
public class ProductRepository : BaseProductRepository
{
public ProductRepository(StoreDBContext context) : base(context)
{
this.context = context;
}
public override async Task<IEnumerable<TResult>> GetTopProducts<TResult>(Func<Product, TResult> selectFunc)
{
var products = this.context.Product
.Select(selectFunc)
.ToList();
return products;
}
}
I am having the generic and expression in the method is because I want to have the caller to define what result should be e.g. partial data from product instead of all the data of a product.
Now i encounter an issue. What if the query is little complex which e.g. more table to join and the resulting data is returning not only the data of the Product, may be the number of users purchased the product etc.
Where can those complex query's which return complex dataset would be?
TResult should be in the 'shape' that the method relates to. It certainly shouldn't be a database entity.
In your case TResult for GetTopProducts would be a collection of product summaries.
class GetTopProductsResult
{
public IEnumerable<Product> TopProducts {get;set;}
public class Product
{
public int Id {get;set;}
public string Name {get;set;}
public int UnitsSold {get;set;}
}
}
I also suggest you look at AutoMapper which will basically implement your Select function in a more structured way.

How to solve "there is already an open datareader associated with this connection"

The main problem is that when the web app is launched to the internet, when the load is high an exception is raised telling that there is already an opened data reader.
The following are the specs we use:
Entityframework 5.0.0
MySQL database
Is there a way of solving this problem without the using(){} block? Main problem of this approach is that when closed the using block I can't expand foreign key relations of entityframework objects inside the html view.
I also attach some source code, showing how we keep a single database context through the whole application
public abstract class AbstractService
{
public Entities db_model
{
get
{
return DbContext.Instance.db_model;
}
}
}
public class DbContext
{
public Entities db_model = new Entities();
private static DbContext _dbContext;
public static DbContext Instance
{
get
{
if(_dbContext == null)
{
_dbContext = new DbContext();
}
return _dbContext;
}
}
}
This answer is specifically related to the issue mentioned in the question about using the loaded entities in an ASP.NET View. The question asks about a way of solving this problem without a using block or disposing of the DbContext, however I am suggesting doing exactly this.
The reason being that it's generally desirable not to use Entity Framework objects in the ASP.NET Views because those objects are a lot more more than just plain POCO objects; they hide logic which allows them to act as a proxy to the underlying database, so they have a hidden dependency on the state of the DbContext which created them.
Here's a contrived example using EF models for Employee and Department with a DbContext:
public class CompanyDbContext : DbContext
{
public DbSet<Department> Departments { get; set; }
public DbSet<Employee> Employees { get; set; }
}
public class Department
{
public long Id { get; set; }
public virtual ICollection<Employee> Employees { get; set; }
}
public class Employee
{
public long Id { get; set; }
public long DepartmentId { get; set; }
public virtual Department Department { get; set; }
}
If these were used in an ASP.NET application, I would create some separate models which aren't tied to Entity Framework, to be used by ASP.NET. For example:
public class DepartmentModel
{
public long Id { get; set; }
public List<EmployeeModel> Employees { get; set; }
}
public class EmployeeModel
{
public long Id { get; set; }
public long DepartmentId { get; set; }
}
A few considerations:
According to the MSDN docs, "A DbContext represents a combination of the UnitOfWork and Repository patterns" - https://learn.microsoft.com/en-us/dotnet/api/system.data.entity.dbcontext?redirectedfrom=MSDN&view=entity-framework-6.2.0 - Therefore the DbContext should be short lived as far as possible.
When loading data from the context, related entities can be retrieved using DbSet<>.Include() - https://learn.microsoft.com/en-us/ef/ef6/querying/related-data
Generally speaking, it makes sense to de-couple the 'data' layer from the 'view' layer - for all kinds of reasons, some of which are listed here: https://learn.microsoft.com/en-us/aspnet/web-api/overview/data/using-web-api-with-entity-framework/part-5 -- this involves mapping between the EF objects and the POCO Models.
The logic which is used to query the DbContext would query the data using EF, and return that data using POCO models so that only logic which deals directly with DbContext has any involvement with the EF objects. For example:
public List<DepartmentModel> GetAllDepartments()
{
using (var ctx = new CompanyDbContext())
{
// Ensure that related data is loaded
var departments = ctx.Departments
.Include(d => d.Employees);
// Manual mapping by converting into a new set of models to be used by the Views
var models = departments
.Select(d => new DepartmentModel
{
Id = d.Id,
Employees = d.Employees
.Select(e => new EmployeeModel
{
Id = e.Id,
DepartmentId = e.DepartmentId
})
.ToList(),
})
.ToList();
return models;
}
}
Being able to use those POCO models, while requiring some extra boilerplate code, provides complete separation between the DbContext and ASP.NET, allowing the data to be used without ASP.NET Views/Controllers being concerned by the lifetime or state of the DbContext.
Sometimes this may look as if this approach violates the 'DRY' principle, however I would point out that EF objects and ViewModel objects exist to solve different problems, and it's not uncommon for the ViewModel objects to take a different shape, or even to require additional fields/attributes which wouldn't be suitable to add to the EF classes.
Lastly, the above uses 'manual' mapping, but if the mappings are really simple and straightforward, then it could make more sense to use AutoMapper instead: Cleanest Way To Map Entity To DTO With Linq Select?

ViewModels in Repository

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.

Updating related entities DDD

I'm confused on how I'm going to updated related entities using DDD. Let say I have a Employee Class and Workschedule Class. How should I updated a specific workschedule of a certain employee? The relationship between Employee and Workschedule is One-To-Many. Below is the code I'm using how to Add/Update a certain workschedule.
public class Employee
{
public int EmployeeId { get; set; }
public virtual ICollection<WorkSchedule> WorkSchedules { get; set; }
public WorkSchedule AddWorkSchedule(WorkSchedule workSchedule)
{
this.WorkSchedules.Add(workSchedule);
return workSchedule;
}
public WorkSchedule EditWorkSchedule(WorkSchedule workSchedule)
{
var originalWorkSchedule = this.WorkSchedules.FirstOrDefault(w => w.WorkscheduleId == workSchedule.WorkscheduleId);
originalWorkSchedule.ClockIn = workSchedule.ClockIn;
originalWorkSchedule.ClockOut = workSchedule.ClockOut;
return originalWorkSchedule;
}
}
public class WorkSchedule
{
public int WorkScheduleId { get; set; }
public DateTime ClockIn { get; set; }
public DateTime ClockOut { get; set; }
public int EmployeeId { get; set; }
}
Is this correct? Did I follow DDD correctly? Also, my thinking right now Workschedule is a value object but I'm putting and ID for normalization purposes
your Model should be "POCO" class
CRUD methods such.. Add or Edit will be considored as part of "Service" or "Repository"
here is a quick idea that just came to my mind / how should it look like and its usage..
IRepository repository { get; set; } //implement Interface and inject via IoC Container
//..usage
var employee = repository.GetEmployee(123); //get by id
//..new WorkSchedule
employee.WorkSchedules.Add(workSchedule);
var result = repository.Save(employee);
Since everything here is EF related, it isn't much of DDD. IF the code works as desired, then it's ok. But DDD has no relationship to EF or any other ORM. You should design the Domain objects, without caring at all about the database or an ORM. Then, in the repository you map the Domain entities to Persistence entities which will be handled by the ORM.
Also, my thinking right now Workschedule is a value object but I'm putting and ID for normalization purposes
This is the consequence when the layers and models are mixed. You don't need an ID in the domain but you need an id for persistence. Trying to fit both requirements in one model and calling that model Domain leads to nowhere.
EF it is not for DDD, it is too clumsy. EF is for same codemonkeys who likes t map SQL tables to Entities and do it like ActiveRecord antipatter, but after more intelligent developers started to call this as a bad practice, they started to use ORM, entities and continue monkeycoding.
I'm struggling with EF last 3 years to let it work DDD way. It successfully resists and wins. Without hacks it doesn't work.
The on-to-many relations still doesn't work as expected, there is not way to create entities with constructor, not the public properties and so on.

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