How to handle paging of sub entities with the repository pattern? - c#

I'm learning domain driven design. I am currently trying to write a simply application in C# designing it using DDD. This application has an aggregate root A which can contain 0..n sub entities B. This could be represented with something along the lines of:
class A {
public int Id { get; }
public IList<B> { get; }
}
with a repository:
class ARepository {
public A Get(int id) { ... }
public void SaveOrUpdate(A root) { ... }
public void Delete(A root) { ... }
}
I would however like to add paging when presenting the B sub entities for a given A instance. How would I go about doing that? The best I can come up with is changing A and ARepository to something like:
class A {
public int Id { get; }
}
class ARepository {
public A Get(int id) { ... }
public void SaveOrUpdate(A root) { ... }
public void Delete(A root) { ... }
public IList<B> GetBForA(A root, int offset, int pageSize, out int numPages) { ... }
}
That would work, for sure, but I would loose the simplicity and elegance of the domain model.
What is the best practice for how to handle paging of sub entities with the repository pattern? I'm not looking for how to deal with this using particular libraries, etc. but rather a way to deal with it on the "pattern level".

The short answer is you should not do it like this. Repository purpose is to make accessing domain objects explicit. They should not be used to page data for UI purposes. That's completely different role which I call Finder. Why? You don't want to pollute your domain (repository belongs to domain) with UI concepts like paging. You can find a more detailed explanation here, on my blog.

If you are using an ORM like NHibernate you can achieve this by setting the collection property (IList) lazy loaded, and eagerly fetch the required page or criteria on the object itself instead of the repository. ex:
var a = ARepository.Get(1);
var secondPageOfBs = a.BList.AsQueryable()
.OrderBy(c => c.Name)
.Skip(PageSize * 2)
.Take(PageSize)
.ToList();
you can also build these queries in the repository and get the result in the domain object like:
var a = ARepository.GetWithPagedChildren(1, PageSize * 2, PageSize);
you can also build more complicated eager queries as described:
http://ayende.com/blog/4367/eagerly-loading-entity-associations-efficiently-with-nhibernate

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.

How to use NHibernate.Criterion in upper layer in app without using reference to NHibernate?

I write a multi-tier app (Data Access Layer,Business Layer, UILayer)
in DAL I use NHibernate to access to DB
then in BusinessLayer I access to DAL to get some data using interface for repository.
And sometimes I need to get data by difficult query. Now I use Linq to extracted data.
I try to wrote metods in repository that implements Criterion logic,but grows up number of overridden methods is wrong way, I think.
public T GetBy(System.Linq.Expressions.Expression<Func<T, bool>> func)
{
return _session.QueryOver<T>().Where(func).List().FirstOrDefault();
}
public IEnumerable<T> GetAllWhere(System.Linq.Expressions.Expression<Func<T, bool>> func)
{
return _session.QueryOver<T>().Where(func).List();
}
public IEnumerable<T> GetAllIn(ICollection collection)
{
return _session.QueryOver<T>().Where(x => x.Id.IsIn(collection)).List<T>();
}
but more and more I need to create difficult criteria to query (I dont like idea of extract all data and filtering it by Linq)
example for criteria that I want to use in BL:
repository.GetMany(x=>
x.Prop1.IsIn(Collection1)&&
x.Prop2.IsIn(Collection2)&&
x.Prop3.IsLike("SomeData")).ToList();
So how I can to use NHibernate.Criterion logic in BL without referensing?
----SOLUTION---
I created class Filter
public class CustomFilter<T>
where T : Entity
{
public class FilterQuery
{
public enum QueryType
{
In, Where, Like, LikeIn,Top
}
public QueryType QType { get; set; }
public Expression<Func<T,object>> Selector { get; set; }
public object Data { get; set; }
public FilterQuery(QueryType qType, Expression<Func<T,object>> selector, object data)
{
QType = qType;
Selector = selector;
Data = data;
}
}
public List<FilterQuery> Queries = new List<FilterQuery>();
public CustomFilter<T> In(Expression<Func<T, object>> selector, ICollection collection)
{
var query = new FilterQuery(FilterQuery.QueryType.In, selector, collection);
Queries.Add(query);
return this;
}
public CustomFilter<T> Top(int i)
{
Queries.Add(new FilterQuery(FilterQuery.QueryType.Top, null,i));
return this;
}
}
And wrote Method in Repository
public IEnumerable<T> GetByFilter(CustomFilter<T> filter)
{
IQueryOver<T,T> query = _session.QueryOver<T>();
foreach (var _filter in filter.Queries)
{
switch (_filter.QType)
{
case CustomFilter<T>.FilterQuery.QueryType.In:
query = query.WhereRestrictionOn(_filter.Selector)
.IsIn((ICollection)_filter.Data);
break;
case CustomFilter<T>.FilterQuery.QueryType.Top :
query = (IQueryOver<T, T>) query.Take((int)_filter.Data);
break;
}
}
return query != null ? query.List<T>() : null;
}
To Use filter I call
var docs = docRepo.GetByFilter(
new CustomFilter<Doc>()
.In(x => x.Archive, arcs)
.Top(200)
).ToList();
There is not an easy way how to turn that feature on or off. In general, there are three approaches, I'd say.
The first is MS and its LINQ. To do that, just use
var query = session.Query<TEntity>()
we (upper layers) can now query that entity as needed...just using LINQ API. Disadvantages is not full coverage of LINQ in NHibernate provider - but it is not so bad at the end. What I do not like here is that you publish lot of your domain ... without some attributes or other AOP ... with one IQueryable you can get the whole system.
The second is the Ayendes approach: The DAL should go all the way to UI. Small cite:
... My current approach is quite different. I define queries, which contains the actual business logic for the query, but I pass that query onward to higher levels of my application. Any additional processing on the query (projections, paging, sorting, etc) can be done. In that way, my queries are closed for modification and open for extension, since they can be further manipulated by higher level code...
read more about it also here: How to organize database layer using NHibernate
The third option is to use some custom solution. E.g. my preferred is to introduce some abstraction, called IFilter, which is passed through layers. Filled on the UI (could be client over API), checked on the BL with all the rules (including some AOP for security) and consumed in DAL .. and converted into the NHibernate Criteria API.
Hope this review helps a bit ... because there is no easy way to say: turn it here on.

How to make Linq2Sql work with my models

I work on a project where we was using SqlConnection, SqlCommand and plain SQL to access repository. Now, I am trying to migrate to Linq2Sql and I want to use the same models. How can I achieve this?
I will reduce the project structure to the minimal meaningful example.
Let's say I have the following classes:
namespace Model
{
public class User
{
public int Id { get; set; }
}
}
All models in Model namespace are one-in-one copy of database entities.
namespace Repository
{
public class UserRepository
{
private _sqlConnectionHelper = new SqlConnectionHelper();
public User GetUser()
{
var reader = _sqlConnectionHelper
.ExecuteAndReturnReader("SELECT * FROM [dbo].[Users]");
while (reader.Read())
{
return new User
{
Id = (int)reader["Id"]
};
}
return null;
}
}
}
Now I am trying to migrate to Linq2Sql. I have created a MyContext.dmbl file with User table in Repository project. It has generated the following class:
namespace Repository
{
[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.Users")]
[global::System.Runtime.Serialization.DataContractAttribute()]
public partial class User: INotifyPropertyChanging, INotifyPropertyChanged
{
private int _ID;
public int ID
{
get
{
return this._ID;
}
set
{
if ((this._ID != value))
{
this.OnIDChanging(value);
this.SendPropertyChanging();
this._ID = value;
this.SendPropertyChanged("ID");
this.OnIDChanged();
}
}
}
// Some other methods
}
}
Now, the problem is that I have a lot of of entities, repositories, models etc. I don't want to change the whole project to use new generated models but not mine from Model namespace. How can I make Linq2Sql work with my models?
It also affects my architecture because in case of these models, the entity and the repository is the same object. I don't need my entities to be CRUD objects. I just want to make minimal changes to project and only use convenient LINQ requests instead of plain SQL like this:
namespace Repository
{
public class UserRepository
{
private MyContextDataContext _myContext = new MyContextDataContext();
public User GetUser()
{
return _myContext.Users.FirstOrDefault();
}
}
}
Or I just don't understand something about purpose and logic of Linq2Sql and it is how it only works like?
Of course, I can write converters or use reflection and make a copy of object property-by-property but it doesn't sound like a good solution.
Ok. Finally, I have found an answer which is pretty simple - Linq2Sql is not a library I was looking for.
There are different approaches for object-relational mapping: code-first, database-first, model-first.
Here is the good StackOverflow article about their differences.
Now, when I learned it, what I have described in my question could be easily rephrased as "how can I make Linq2Sql be code-first". The answer is simple - I cannot do this.
As a result of some investigations, I have understood that I was looking for Entity Framework which perfectly fit in my project.
Now, my repository looks like this:
namespace Repository
{
public MyContextDataContext : DbContext
{
public DbSet<User> Users { get; set; }
}
public class UserRepository
{
private MyContextDataContext _myContext = new MyContextDataContext();
public User GetUser()
{
return _myContext.Users.FirstOrDefault();
}
}
}

Mapping database entities to domain entities via repositories - static property or separate service?

I am working on an application where my database schema does not match up well to my domain model, and modifications to the database schema are not under my control. Because of this, I end up doing a lot of mapping in my repository calls, and I have many concrete repos to handle the mapping to and from the database (using entity framework database-first). What I am looking for is an elegant way to make calls to my repositories based on the domain entity object type. Thus far, the domain model itself is still very anemic, as we are still in the process of defining business rules.
I have seen an example elsewhere (can't recall the link) where the repository calls were passed through the domain entities via a static property, but I do not know if this will present threading issues or whether it violates any domain model principles, especially if we decide to implement DI/IoC down the road.
Here is an example of what I have so far. For the sake of brevity, I have simplified the mapping calls to the database, as the mapping in the actual application is more complex.
Repository example:
public interface IRepository<T>
{
T GetById(int id);
void Save(T entity);
}
public abstract class RepositoryFactory<T> : IRepository<T>
{
protected MyDbContext db;
protected int userId;
protected RepositoryFactory()
{
this.db = new MyDbContext();
this.userId = WebSecurity.GetCurrentUser().UserId;
}
public abstract T GetById(int id);
public abstract void Save(T entity);
}
public class CustomerRepository : RepositoryFactory<Customer>
{
public override void Save(Customer customer)
{
var entity = db.customers.FirstOrDefault(p => p.customerid == customer.Id && p.users.userid == userId);
if (entity == null) return; // TODO: Add error trapping
// Mapping (lots of reshaping happening here)
entity.customername = customer.Name;
entity.customeraddress = customer.Address;
// ...
// Save changes to DB
db.Entry(entity).State = EntityState.Modified;
db.SaveChanges();
}
public override Customer GetById(int id)
{
var entity = db.customers.FirstOrDefault(p => p.customerid == id && p.users.userid == userId);
if (entity == null) return null; // TODO: Add error trapping
return new Customer
{
Name = entity.customername,
Address = entity.customeraddress,
// ...
};
}
}
Domain Entity example:
public class Entity { public int Id { get; set; } }
public class Customer : Entity
{
public string Name { get; set; }
public string Address { get; set; }
// Does this violate any domain principles?
public static IRepository<Customer> Repository
{
get { return new CustomerRepository(); }
}
}
With this code, from my controller I can do something like:
Customer customer = Customer.Repository.GetById(id);
Instead of:
IRepository<Customer> repo = new CustomerRepository();
Customer customer = repo.GetById(id);
This seems like a very elegant solution to my problem, and it also keeps me from needing to include the Repository namespace in my controllers (MVC). If this smells funny and there is a better way to handle this, I'd love to learn. The only other thing I can think of is creating a separate crud service to handle my repository calls, but I imagine for that I would need a dictionary or hash table to map my concrete repos to my domain model objects, and that seems like it would be a maintenance nightmare.
I'd suggest using an inversion of control (dependency injection) container and injecting your repositories into your controllers or wherever. This way you can use them like this:
public class HomeController : Controller
{
private readonly IRepository<Customer> _customerRepository;
public HomeController(IRepository<Customer> customerRepository)
{
_customerRepository = customerRepository;
}
public ActionResult Index(int id)
{
var customer = _customerRepository.GetById(id)
return View(customer);
}
}
This way, if you ever need to replace CustomerRepository class, or need to have multiple versions (say CustomerRepositoryEntityFramework or CustomerRepositoryNHibernate) you can simply replace a new class inheriting from IRepository and your controller code will still continue to work with no change.
I recommend using Castle Windsor, or Ninject, or one of the many other IoC containers.
Also, you generally want to keep your domain entities as poco's (Plain Old CLR Object). This means separating everything out of your entities including validation, business rules, etc. and simply having only its properties. This allows you to pass your domain entities through the pipeline more easily, specially since you are in the early stages of development. This will offer you the most flexibility in the future.

NHibernate mappings issue when referencing class (lazy load issue?)

I'm using NHibernate + Fluent to handle my database, and I've got a problem querying for data which references other data. My simple question is: Do I need to define some "BelongsTo" etc in the mappings, or is it sufficient to define references on one side (see mapping sample below)? If so - how? If not please keep reading.. Have a look at this simplified example - starting with two model classes:
public class Foo
{
private IList<Bar> _bars = new List<Bar>();
public int Id { get; set; }
public string Name { get; set; }
public IList<Bar> Bars
{
get { return _bars; }
set { _bars = value; }
}
}
public class Bar
{
public int Id { get; set; }
public string Name { get; set; }
}
I have created mappings for these classes. This is really where I'm wondering whether I got it right. Do I need to define a binding back to Foo from Bar ("BelongsTo" etc), or is one way sufficient? Or do I need to define the relation from Foo to Bar in the model class too, etc? Here are the mappings:
public class FooMapping : ClassMap<Foo>
{
public FooMapping()
{
Not.LazyLoad();
Id(c => c.Id).GeneratedBy.HiLo("1");
Map(c => c.Name).Not.Nullable().Length(100);
HasMany(x => x.Bars).Cascade.All();
}
}
public class BarMapping : ClassMap<Bar>
{
public BarMapping()
{
Not.LazyLoad();
Id(c => c.Id).GeneratedBy.HiLo("1");
Map(c => c.Name).Not.Nullable().Length(100);
}
}
And I have a function for querying for Foo's, like follows:
public IList<Foo> SearchForFoos(string name)
{
using (var session = _sessionFactory.OpenSession())
{
using (var tx= session.BeginTransaction())
{
var result = session.CreateQuery("from Foo where Name=:name").SetString("name", name).List<Foo>();
tx.Commit();
return result;
}
}
}
Now, this is where it fails. The return from this function initially looks all fine, with the result found and all. But there is a problem - the list of Bar's has the following exception shown in debugger:
base {NHibernate.HibernateException} = {"Initializing[MyNamespace.Foo#14]-failed to lazily initialize a collection of role: MyNamespace.Foo.Bars, no session or session was closed"}
What went wrong? I'm not using lazy loading, so how could there be something wrong in the lazy loading? Shouldn't the Bar's be loaded together with the Foo's? What's interesting to me is that in the generate query it doesn't ask for Bar's:
select foo0_.Id as Id4_, foo0_.Name as Name4_ from "Foo" foo0_ where foo0_.Name=#p0;#p0 = 'one'
What's even more odd to me is that if I'm debugging the code - stepping through each line - then I don't get the error. My theory is that it somehow gets time to check for Bar's during the same session cause things are moving slower, but I dunno.. Do I need to tell it to fetch the Bar's too - explicitly? I've tried various solutions now, but it feels like I'm missing something basic here.
This is a typical problem. Using NHibernate or Fluent-NHibernate, every class you use that maps to your data is decorated (which is why they need to be virtual) with a lot of stuff. This happens all at runtime.
Your code clearly shows an opening and closing of a session in a using statement. When in debugging, the debugger is so nice (or not) to keep the session open after the end of the using statement (the clean-up code is called after you stop stepping through). When in running mode (not stepping through), your session is correctly closed.
The session is vital in NH. When you are passing on information (the result set) the session must still be open. A normal programming pattern with NH is to open a session at the beginning of the request and close it at the end (with asp.net) or keep it open for a longer period.
To fix your code, either move the open/close session to a singleton or to a wrapper which can take care of that. Or move the open/close session to the calling code (but in a while this gets messy). To fix this generally, several patterns exist. You can look up this NHibernate Best Practices article which covers it all.
EDIT: Taken to another extreme: the S#arp architecture (download) takes care of these best practices and many other NH issues for you, totally obscuring the NH intricacies for the end-user/programmer. It has a bit of a steep learning curve (includes MVC etc) but once you get the hang of it... you cannot do without anymore. Not sure if it is easily mixed with FluentNH though.
Using FluentNH and a simple Dao wrapper
See comments for why I added this extra "chapter". Here's an example of a very simple, but reusable and expandable, Dao wrapper for your DAL classes. I assume you have setup your FluentNH configuration and your typical POCO's and relations.
The following wrapper is what I use for simple projects. It uses some of the patterns described above, but obviously not all to keep it simple. This method is also usable with other ORM's in case you'd wonder. The idea is to create singleton for the session, but still keep the ability to close the session (to save resources) and not worry about having to reopen. I left the code out for closing the session, but that'll be only a couple of lines. The idea is as follows:
// the thread-safe singleton
public sealed class SessionManager
{
ISession session;
SessionManager()
{
ISessionFactory factory = Setup.CreateSessionFactory();
session = factory.OpenSession();
}
internal ISession GetSession()
{
return session;
}
public static SessionManager Instance
{
get
{
return Nested.instance;
}
}
class Nested
{
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static Nested()
{
}
internal static readonly SessionManager instance = new SessionManager();
}
}
// the generic Dao that works with your POCO's
public class Dao<T>
where T : class
{
ISession m_session = null;
private ISession Session
{
get
{
// lazy init, only create when needed
return m_session ?? (m_session = SessionManager.Instance.GetSession());
}
}
public Dao() { }
// retrieve by Id
public T Get(int Id)
{
return Session.Get<T>(Id);
}
// get all of your POCO type T
public IList<T> GetAll(int[] Ids)
{
return Session.CreateCriteria<T>().
Add(Expression.In("Id", Ids)).
List<T>();
}
// save your POCO changes
public T Save(T entity)
{
using (var tran = Session.BeginTransaction())
{
Session.SaveOrUpdate(entity);
tran.Commit();
Session.Refresh(entity);
return entity;
}
}
public void Delete(T entity)
{
using (var tran = Session.BeginTransaction())
{
Session.Delete(entity);
tran.Commit();
}
}
// if you have caching enabled, but want to ignore it
public IList<T> ListUncached()
{
return Session.CreateCriteria<T>()
.SetCacheMode(CacheMode.Ignore)
.SetCacheable(false)
.List<T>();
}
// etc, like:
public T Renew(T entity);
public T GetByName(T entity, string name);
public T GetByCriteria(T entity, ICriteria criteria);
Then, in your calling code, it looks something like this:
Dao<Foo> daoFoo = new Dao<Foo>();
Foo newFoo = new Foo();
newFoo.Name = "Johnson";
daoFoo.Save(newFoo); // if no session, it creates it here (lazy init)
// or:
Dao<Bar> barDao = new Dao<Bar>();
List<Bar> allBars = barDao.GetAll();
Pretty simple, isn't it? The advancement to this idea is to create specific Dao's for each POCO which inherit from the above general Dao class and use an accessor class to get them. That makes it easier to add tasks that are specific for each POCO and that's basically what NH Best Practices was about (in a nutshell, because I left out interfaces, inheritance relations and static vs dynamic tables).

Categories

Resources