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.
Related
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.
I have a concern. I want to know how can we make use of in-memory class in c# .Net using MVC 4 in Visual Studio 2010. i mean to say i do not want to use database or any other external storage medium even repository.
I want to store Data, retrieve data from that class.
I heard about "Caching" but it have its own limitations.
I also not to use any type of repositories, because using repository, i have made already using http://www.edandersen.com/2013/05/30/asp-net-mvc-basics-part-2-viewmodel-to-model-mapping-and-editing/.
So can you suggest me how to do this?
What's your goal?
If the data is important to persist you can't have it in memory. IIS apps can restart at any time due to many reasons. The data is then lost without notice.
If the data is meant as a cache either use indeed a cache or a static variable (with proper synchronization).
You could use a static object instance. For example, let's say that you have a User class:
public class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
and then have a static container for your entities:
public static class Container
{
static Container()
{
Users = new ConcurrentBag<User>();
}
public static IEnumerable<User> Users { get; set; }
...
}
And then you can access this static instance from anywhere in your code. Obviously since ASP.NET MVC is a multithreaded environment you will need to properly synchronize the access to those variables. For example using ConcurrentBag<User> instead of a List<User> implementation.
and then in your controller you could access your in-memory data store:
public ActionResult Index(int id)
{
var user = Container.Users.FirstOrDefault(x => x.Id == id);
if (user == null)
{
return HttpNotFound();
}
return View(user);
}
I am implementing CQRS and I am a little confused on the how quickly number of queries are getting.
I have googled it too but due to variety of flavors of CQRS I am not getting any appropriate solution. Perhaps I'm doing something wrong here? Here's my code and respective queries.
class User {
public int Id { get; set; }
public string Username { get; set; }
public string Status { get; set; }
public string Role { get; set; }
// ...
}
And I want to find user by its username, so I have written query for it
abstract class Query<TResult> { }
class FindUserByStatusQuery : Query<IEnumerable<User>> {
public string Status;
}
and the respective handler for it
interface IQueryHandler<TQuery, TResult> where TQuery : Query<TResult>
{
TResult Handle(TQuery query);
}
class FindUserByStatusQueryHandler : IQueryHandler<FindUserByStatusQuery, IEnumerable<User>>
{
public IEnumerable<User> Handle(FindUsersByAcountStatusQuery query)
{
using (Entities db = new Entities())
{
status = query.status.ConvertToString();
return db.Users.Where(u => u.Status.Contains(status)).ToArray();
}
}
}
Now, I want to look-up user by other fields too like by Id or by multiple fields (by both status & role). And there could be more queries like that.
My question is do I need to create separate query classes for them? Wouldn't that make number of queries quite high? How can I limit that?
I find the best approach is to be pragmatic - make the query fit the context of the current situation, and dont think beyond that.
You say they could query by status and role at the same time, so include both of those properties on the query object.
If you reuse the query 'somewhere else' in the domain, and it needs further search criteria, create a new query specifically for that domain problem.
Free yourself from the burden of 'limiting code' and deal with each situation separately. Creating objects that deal with multiple domain scenarios leads to complexity, regression issues and brittle classes.
Give your types a single responsibility
Need an advise on the "best" way to implement Update and Delete operations on complex nested DTOs. For very simple example, suppose we have this structure:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Employer Company { get; set; }
}
public class Employer
{
public string Name { get; set; }
public string Address1 { get; set; }
public string City { get; set; }
public string State { get; set; }
}
An update to Person as per Employer here can mean several things:
1. Previously there was no Employer for Person and we need to do insert to DB to introduce new Employer.
2. There was an Employer previously and we are just updating the Employer's inner Data
3. Employer has been removed from Person
Question:
If you have a domain/business compnent object something like PersonBusinessComponent with some method like PersonBusinessComponent.Update(Person)
What is the best way to identify which scenario being executed and apply changes -- meaning if it is a delete operation then we'll call some EmployerDALC.Delete method or if it is an Insert then obviously EmployerDALC.Insert etc...
I understand that one option is to get current version from Database and then tediously compare for existence of every nested object within Person, but I hope there is some better way or even probably more generic way that can be implemented to handle any such operations in the whole solution.
Note: I am not using MS Entity Framework.
It depends on the architecture of your system. Is this a Procedural model, an ActiveRecord model or a Domain Model? I see you're using DTOs so that would imply a Domain model.
If so then your business logic (inside the 'Services' tier) would be responsible for orchestrating the operations, for example:
public interface PersonManager
{
void CreateNewPerson(Person person);
void DeletePerson(Person person);
void ModifyPerson(Person person);
// ... and so on .../
}
The PersonManager would then be responsible for examining the object and working out what to do with it based on the method run.
It would then defer down to its own business logic layer (which can converse with the DAL) to work out exactly how that should be achieved. For example with the Modify method it can query the DAL to get the current Employer's for that Person, defer to a ModifyEmployer if the employer has changed etc:
public void ModifyPerson(Person person)
{
var currentEmployer = DAL.Employers.Get(Person.Employer.EmployerID);
if (currentEmployer != person.Employer)
{
// Try and get a matching Employer from the appropriate Service (liaising with the DAL)
var employer = EmployerManager.GetEmployer(person.Employer.EmployerID);
if (employer == null)
{
// ... Create a new employer
}
else if (employer != person.Employer)
{
// ... Update existing employer
}
}
// ... Now go ahead and handle any changes to the person
}
Off the top of my head I can't think of any particular package to handle this for you, generally I'd say it's all in the architecture of your system and how the BL talks to the DAL, but I'm sure one of the brain-boxes here will come up with some better suggestions :)
Hope that might help a little bit!
K.
So I will call a repository to retrieve the root object of a complex object graph, using FluentNHibernate. But for some sub-level objects I don't want to retrieve all elements, but only those where a date parameter equals certain condition. In below code, I want the lower level Order object to be filtered in this way by the OrderTime field.
Meaning I want to retrieve all UserGroups, with all Users, but the Orders object of each User shall only contain orders from a specific date or date range.
So what are my options on how to retrieve this object graph? I don't want lazy loading, I just want to specify a handful of different retrieval conditions, which will never change. So they can be separate functions of the repository, like suggested at the end. But how would I go about coding those methods, how to specify these conditions?
Objects:
public class UserGroup
{
public int Id;
public IList<User> Users;
}
public class User
{
public int Id;
public string Name;
public IList<Order> Orders;
}
public class Order
{
public int Id;
public decimal Price;
public System.DateTime OrderTime;
}
Repository:
public class UserGroupRepository
{
public List<UserGroup> GetAll()
{
using (ISession session = FNH_Manager.OpenSession()) {
dynamic obj = session.CreateCriteria(typeof(UserGroup)).List<UserGroup>();
return obj;
}
}
}
Potential new Repository methods: ?
public List<UserGroup> GetAll_FilterOrderDate(System.DateTime _date)
{
}
public List<UserGroup> GetAll_FilterOrderDate(List<System.DateTime> _dates)
{
}
It really depends on what you want to do with the orders.
Is there a reason you need to query on the aggregate root? Would it make sense to query over the actual orders by date instead? So you'd end up with:
session.QueryOver<Order>().Where(t => t.OrderDate > ...);
If your associations are set up correctly you'll still be able to navigate to the user.
Personally I find the repository pattern to be a bit restrictive and would rather use query objects, so you'd end up with something like:
queryService.FindAll<UserGroup>(new GetAllByFilterOrderDate(DateTime.Now));
However if the concept of a repository works for you then by all means stick to it, but it means you'll try to force your object model into this 'UserGroup' centric view.