-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 14 posts ] 
Author Message
 Post subject: Arquitecture question repository pattern
PostPosted: Tue Sep 25, 2007 7:19 am 
Newbie

Joined: Tue Sep 25, 2007 6:43 am
Posts: 16
I want to use NHibernate for an existing Database.

Table Product has a m:n relation to table Kit. This relation is described in a table Product_Kit which has
- ProductID
- KitID
- IsMain (bit)
- IsSpecial (bit)

I want to use a repository pattern, in which the business layer is completely ignorant of it's usage in a database context.
so...

public class Kit
{
...
private List<Product> products;
public List<Product> Products
{get/set from products;}

public List<Product> SpecialProducts
{
get{?}
}

public void AddSpecialProduct(Product p)
{....}
}

How would you go on filling SpecialProducts in a DAO? Right now I am using an orm (some kind of active record pattern) employing no separation between dao and businesslayer so this is quite doable, but I cannot get it right in my head how to do something like this in a repository pattern....

Any hints on how to go about this in nh greatly appreciated!

--Jan[/list]


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 26, 2007 7:02 am 
Beginner
Beginner

Joined: Mon May 14, 2007 2:50 am
Posts: 22
What I do:
1. I use my entity classess as a way to store data, and nothing else.
2. All methods working with that class go into other special class, for example ProductService.
If you need to load specialProduct, then i would create specialproduct service, which would return only special products.

Does that help?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 16, 2007 11:21 am 
Newbie

Joined: Tue Sep 25, 2007 6:43 am
Posts: 16
Sorry for the late answer!

I think the Entity/EntityService pattern seems interesting, but how would such an implementation look like?

Code:
Kit k = kitDao.GetById(234);
KitService.FillWithSpecialproducts(k);
KitService.FillWithEssecialProducts(k);


... and so on? A bit cubersome and errorprone, as I cannot rely on receiving a "complete" business entity and apply business logic to it.

Or does the property IList<Product> Kit.SpecialProducts call the service? This would bring the dao into the business layer, I suppose. Certainly I would want to avoid this (even if it's only an interface).

On the other hand the dao could call these methods in GetById, but them I would put business logic in the data layer, wouldn't I?

I am a bit confused, certainly I am missing something...

Jan

PS: I posted another question just a few minutes back, which refers to a question, that arose when I was in the process of refactoring my domain from active record to repository pattern (and gentle.net to nhibernate).

So this other post reflects the present, whereas this represents, where I actually want to go :)


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 16, 2007 12:49 pm 
Beginner
Beginner

Joined: Mon May 14, 2007 2:50 am
Posts: 22
JanLimpens wrote:
Sorry for the late answer!

I think the Entity/EntityService pattern seems interesting, but how would such an implementation look like?

Code:
Kit k = kitDao.GetById(234);
KitService.FillWithSpecialproducts(k);
KitService.FillWithEssecialProducts(k);


... and so on? A bit cubersome and errorprone, as I cannot rely on receiving a "complete" business entity and apply business logic to it.


Yes, it is very cumbersome, but very straightforward.
However, I always use this rule - use the simplest thing that works for you. And do not forget unit testing!


Sometimes people tend to over-design everything, and make everything very complicated. It's hard to tell what is the best solution for you without knowing how big your app is, and what is the context. Only you can judge it best.


Quote:
Or does the property IList<Product> Kit.SpecialProducts call the service?
This would bring the dao into the business layer, I suppose. Certainly I would want to avoid this (even if it's only an interface).

No, a bad solution this would be. I would not do it.
[/quote]


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 16, 2007 5:51 pm 
Newbie

Joined: Tue Sep 25, 2007 6:43 am
Posts: 16
Architecturewise, do your services live in the dao?

So it would actually be...

Kit k = kitDao.GetById(234);
k.SpecialProducts = kitDao.FindSpecialProducts(k);
k.EssentialProducts = kitDao.FindEssentialproducts(k);


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 16, 2007 9:11 pm 
Regular
Regular

Joined: Fri Jan 20, 2006 7:45 pm
Posts: 97
Location: San Antonio, TX
JanLimpens wrote:
Architecturewise, do your services live in the dao?

So it would actually be...

Kit k = kitDao.GetById(234);
k.SpecialProducts = kitDao.FindSpecialProducts(k);
k.EssentialProducts = kitDao.FindEssentialproducts(k);


If I may join in...
Risking a flame war I'll say that I take a similar approach and would answer no...and yes. There are a lot of debate regarding the difference between Repository and DAO. I'd say that the key point is that a Respository should offer enough abstraction such that the persistence mechanism is transparent to the user (programmer). It should also appear high level enough so that the team's business members can look at the code and have an idea of what's going on (and without their eyes glazing over).

Some Java guys will say that the two are synonymous, but the historic view of DAOs within the Microsoft community makes keeping the two ideas separate key in my opinion.

In my current system I have objects that I call DAOs that do nothing more than support core CRUD operation (and some limited ADHOC query capabilities) on an entity by entity basis. The interface to the DAOs is agnostic in regard to the actual persistence mechanism and I have an NHibernate-specific implementation of the interface (I could write another from scratch using straight ADO and the business layer wouldn't know the difference). The adhoc queries are supported because the DAO interface is generic to cover all entity types, so added functions that support stuff like getting objects with a field in a certain data range to DAO implementations doesn't make a whole lot of sense to me.

My respository classes, on the other hand, do not support adhoc queries and are really only used in terms of objects (heck, I usually retrieve stuff from the repository by passing back an "example" object that's used to create the criteria needed). For all the application know the data could be held in memory using Prevaylor or Bamboo. The repository knows the appropriate DaoFactory to use to and the business layer knows nothing more than the repository services.

_________________
Dum spiro, spero
-------------------------------
Rate my post if it helps...


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 16, 2007 10:20 pm 
Newbie

Joined: Tue Sep 25, 2007 6:43 am
Posts: 16
But does not taking this road mean to abandon the nhibernate features such as relation mapping?

So far my DAO layer works in the same way as you describe, providing the basic CRUD implementation, offered by a base class using generics. My DAO also has a GetByExample(<T> entity) method, so probably I mix your understanding from a DAO with that of a repository.
I rely on interfaces, so employing IoC, the domain layer is completely ignorant on how data is saved and where it comes from.

Now if one uses the said service methods and having the completeness of an object depend on the client developer (instead of just retrieving an object, one needs to separately and manually initialize all collections), IMHO calls for trouble. Business logic could rely on having certain collection be present and up to date.

If I had a ShoppingCart class with a GrandTotal getter, that is fed from a collection of Order objects' Value, I rely on the collection being filled and up to date. Checking all the time, if the collection is filled and if not so, refilling it does not seem very reliable to me. I thought NHibernate should take care of exactly this type of requirement (among other things).

So I am asking myself, if one willfully does not use this feature, what are the motives?


Top
 Profile  
 
 Post subject:
PostPosted: Wed Oct 17, 2007 12:04 pm 
Beginner
Beginner

Joined: Mon May 14, 2007 2:50 am
Posts: 22
JanLimpens wrote:
So far my DAO layer works in the same way as you describe, providing the basic CRUD implementation, offered by a base class using generics.

Could I ask what was the reasong that made you make CRUD implementations, and then offer those implementations by a base clase?

Personally, i see no reason for having those, because the CRUD implementation using Castle.ActiveRecord is as simple as saying
Code:
ActiveRecordMediator.Save(object)
ActiveRecordMediator.Delete(object)
ActiveRecordMediator.FindById(id)

and this code is the same for all persisten classes. ActiveRecordMediator just takes any persistent classs and just saves it using current opened session. What else to implement here? Maybe you have specific needs, if yes, would be nice to hear them.


Quote:
I rely on interfaces, so employing IoC, the domain layer is completely ignorant on how data is saved and where it comes from.
jlockwood tells the same:
The interface to the DAOs is agnostic in regard to the actual persistence mechanism and I have an NHibernate-specific implementation of the interface

Why do you actually need persistence agnostic mechanism?
I mean, will you ever change NHibernate to something else? Every data source has very very specific behaviour. Databases have one behaviour, files have other, in-memory persistence the other, etc. In any case, performance is more important than the possibility, that one day for some unknown reason you might want to save all data not to databse, but to file. I putting this very bluntly, don't get offended. I just want to undertand what are your motives.
NHibernate already gives you a database agnostic framework, why do you need to be agnostic from whole persistence mechanism?


Concerning the DAO and Repository, (though I do not get completely what are they exactly), I believe we use neither of them for some specific reasons.
The main is that our desktop app supports many-step undo mechanism. For examle, you can open one window, then another, and so on and so on, up to as many windows as you want (we don't impose any limit), but only when you close the first window, only then all changes go to dabase. You can choose to cancel all changes that you made in other windows (even if you pressed "Save" button), and they will not go to database, and the state will not change.
This we implement very straighforwardly - we have a list of database actions, which are executed only when the first window is saved. When any of the child windows execute save, we do not execute any statements againts the db. And the statements are pretty simple. For example, a database action list might look like this
Code:
ActiveRecordMediator.Save(new Company())
ActiveRecordMediator.Save(Client)  // the client is related to company
ActiveRecordMediator.Delete(Client) // the client, which was related to company
ActiveRecordMediator.Save(new Account()) // account for the company
ActiveRecordMediator.Save(new Client()) // client related to compay
ActiveRecordMediator.Save(new Account()) // account related to client
etc

And so on. This has a side effect, that the same object might be saved many time when you actually save the object, but we see it as not a problem. More important is the feature that this way of doing things provides us.
And for this reason we do not need any DAO or any Repository.

Yes, of course, we still have things like ILoadingService, which is a service which knows what associations to load eagerly for specific object, but at the moment every persistent class has only one such service. In future we might expand this interface to support context specific loading services, thought there are ways to automagically retrieve what relations need to loaded eagerly.

Now, to sum up. I believe all this discussion does not help you, JanLimpens :) However, the best part which you can get here is that there is no best solution, and DAO and Repositories are a very very specific for every situtation, so you will have to judge on yourself or with your team together.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Oct 17, 2007 1:14 pm 
Newbie

Joined: Tue Sep 25, 2007 6:43 am
Posts: 16
Hello dark cloud,

imho, exposing a catch it all dao (and as I understand it, the active mediator is just this) is calling for trouble, just as using object as an argument is (in many cases).

What happens, if someone tries to persist something that has no correspondent table in the database? Maybe no exception is thrown, but what happens is not obvious.

The concrete implementation of a generic base class is actually a one liner and it has the advantage to expose the system's capabilities at compile time.
ProductDao.Save(Product p) will not accept anything, that it cannot deal with.

I do not use ActiveRecord, because I dislike the pattern. It leads to a bleeding between the data layer and the business layer. I don´t know if I can use the ActiveRecordMediator for classes that do not inherit ActiveRecordBase (or however it is called). Inheriting from ActiveRecordBase means bringing a tight coupled reference to the data layer to the domain. And I have yet to see the case, where this does not lead to bad design :)

Quote:
Code:
ActiveRecordMediator.Save(new Company())
ActiveRecordMediator.Save(Client)  // the client is related to company
ActiveRecordMediator.Delete(Client) // the client, which was related to company
ActiveRecordMediator.Save(new Account()) // account for the company
ActiveRecordMediator.Save(new Client()) // client related to compay
ActiveRecordMediator.Save(new Account()) // account related to client


The problem is, that you have got to know the inner workings of the db, to handle your domain. I don't think this is very elegant...

I´d prefer something along the lines....

Code:
Company co = new Company();
co.AddClient(new Client("Sony"));
co.GetClient("Sony").AddAccount(new Account("Some Account"));
CompanyDaoRepositoryOrWhatever.Save(co);

co.RemoveClient("Sony");
CompanyDaoRepositoryOrWhatever.Save(co);


Sorry for the curiosity, I am very eager to understand, why people take certain design decisions and to learn from then. In this case I guess I have to disagree ;)

Many thanks for the kind responses!

Jan


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 18, 2007 6:29 am 
Beginner
Beginner

Joined: Mon May 14, 2007 2:50 am
Posts: 22
Code:
What happens, if someone tries to persist something that has no correspondent table in the database? Maybe no exception is thrown, but what happens is not obvious.

Well, i see this as a no problem. :) This is a human-prone error, you could also make other simple mistakes. If you want to save a class, which is not persistent, then it is a bug, you will never want to do that.
If you want compile time checking, you can use generic version of the ActiveRecordMediator, witch can do the compile-time checking for you.

(p.s. it will throw an exception.)


Quote:
I do not use ActiveRecord, because I dislike the pattern. It leads to a bleeding between the data layer and the business layer. I don´t know if I can use the ActiveRecordMediator for classes that do not inherit ActiveRecordBase (or however it is called). Inheriting from ActiveRecordBase means bringing a tight coupled reference to the data layer to the domain.

No, you dot need to inherit from ActiveRecordBase. What does activeRecordBase is acdtually forwarding all calls to ActiveRecordMediator. ActiveRecordBase is a helper class, which is not obligatory to use.
And yes, ActiveRecordMediator can work with classes wich do not inherit from ActiveRecordBase, they just have to be registered in NHibernate.



Quote:
Quote:
Code:
ActiveRecordMediator.Save(new Company())
ActiveRecordMediator.Save(Client)  // the client is related to company
ActiveRecordMediator.Delete(Client) // the client, which was related to company
ActiveRecordMediator.Save(new Account()) // account for the company
ActiveRecordMediator.Save(new Client()) // client related to compay
ActiveRecordMediator.Save(new Account()) // account related to client


The problem is, that you have got to know the inner workings of the db, to handle your domain. I don't think this is very elegant...

Now here i do not agree at all.
Where do you see the inner workings of the DB? NHibernate is database agnostic, so what you see here is a single call to NHibernate, which then in turn saves your data to whatever databse you are connected to. Here is no database specific operations.
Now if you want to optimize your application to achieve better performance, you have to execute these calls to NHibernate in a certain way, which is what you do every time you want to optimize your performance - you shuffle around the operations so that they are bundled together, or called in a specific manner.



Quote:
I´d prefer something along the lines....
Code:
Company co = new Company();
co.AddClient(new Client("Sony"));
co.GetClient("Sony").AddAccount(new Account("Some Account"));
CompanyDaoRepositoryOrWhatever.Save(co);
co.RemoveClient("Sony");
CompanyDaoRepositoryOrWhatever.Save(co);


This example is ok, nothing to add.
This example is also database agnostic.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 18, 2007 12:51 pm 
Regular
Regular

Joined: Fri Jan 20, 2006 7:45 pm
Posts: 97
Location: San Antonio, TX
@DK
Quote:
Why do you actually need persistence agnostic mechanism?
I mean, will you ever change NHibernate to something else?

Sadly, the probability is fairly high. I'm working on a govt contract and some in mgt are trying to micromanage the project and kill use of all the open source tools that I'm currently using (even though I have used it on other govt projects, providing the tools source with tyhe deliverables). The agnostic mechanism can be a pain in the rear but I want to minimize code changes that will be required if I loose this political battle.

Quote:
Every data source has very very specific behaviour. Databases have one behaviour, files have other, in-memory persistence the other, etc. In any case, performance is more important than the possibility, that one day for some unknown reason you might want to save all data not to databse, but to file. I putting this very bluntly, don't get offended. I just want to undertand what are your motives.

I understand, am not offended, and appreciate your candor. The respository's implementation is centered on database use (has transaction mgt, etc), but session mgt, auditing and what-not is not something that the user has to deal with directly. As the app is currently, it's pretty easy to add support for new entities, fairly easy to maintain (its size is the greatest factor in complexity), and I can get a junior developer up and running pretty quick (which is nice because I have another engagement in the queue that I'm anxious to move to).

Regarding performance, the application is well within user exceptions. Besides, if I too terribly worried about performance I wouldn't be using NHibernate as much. I am, however, terribly concerned with maintenance. This approach has (so far) helped with maintenance and the performance of MS Vista has improved user perception of system performance accross the board (LOL, so long as Vista keeps the bar so low).

Regarding using other types of datastores, the repository interface is such that it probably COULD support an in-memory data store if I really wanted it (but I don't for many reasons). What I was trying to highlight was that the abstraction offered by the repository makes (should at least) data access much simpler from the programmer's stand point.
NHibernate already makes things much simlper and easy to read, but as you know things can still get a bit complicated.

_________________
Dum spiro, spero
-------------------------------
Rate my post if it helps...


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 18, 2007 1:21 pm 
Regular
Regular

Joined: Fri Jan 20, 2006 7:45 pm
Posts: 97
Location: San Antonio, TX
@Jan
Code:
Now if one uses the said service methods and having the completeness of an object depend on the client developer (instead of just retrieving an object, one needs to separately and manually initialize all collections), IMHO calls for trouble. Business logic could rely on having certain collection be present and up to date.

I agree completely.
Code:
If I had a ShoppingCart class with a GrandTotal getter, that is fed from a collection of Order objects' Value, I rely on the collection being filled and up to date. Checking all the time, if the collection is filled and if not so, refilling it does not seem very reliable to me. I thought NHibernate should take care of exactly this type of requirement (among other things).

Yes, lazy loading and caching takes care of such things. In fact, I would say that this is a selling point. As far as GrandTotal, you could use an aggregate function if the total needed much more often than the Order collection. The scalar value could be present but actual loading of the collection could be deferred. There are hundreds of ways to skin a cat.

Quote:
What happens, if someone tries to persist something that has no correspondent table in the database? Maybe no exception is thrown, but what happens is not obvious.

Above all, and I think DarkCloud had said the same on another post, TESTING. Also fanatical adherence to the Principle Of Least Surprise.

Quote:
I do not use ActiveRecord, because I dislike the pattern. It leads to a bleeding between the data layer and the business layer. I don´t know if I can use the ActiveRecordMediator for classes that do not inherit ActiveRecordBase (or however it is called). Inheriting from ActiveRecordBase means bringing a tight coupled reference to the data layer to the domain. And I have yet to see the case, where this does not lead to bad design :)

I tend to agree, not sure if it's because of my Java days. Now if we were coding in ruby...

Quote:
The problem is, that you have got to know the inner workings of the db, to handle your domain. I don't think this is very elegant...

...Ergo Respository, no?

Quote:
Sorry for the curiosity, I am very eager to understand, why people take certain design decisions and to learn from then. In this case I guess I have to disagree ;)

Many thanks for the kind responses!

Ah, you should never apologize for curiosity! I think that healthy dialog is crucial in all matters. Some folks seem to have a hard time with the idea of being wrong or looking foolish and thus shy from debate. I tend to believe that we are all wrong to some degree or other (and of course conversely right to some degree or other).

...parhaps this somewhat postmodern paradigm serves as the impetus behind the agnostic services in my system (LOL).

_________________
Dum spiro, spero
-------------------------------
Rate my post if it helps...


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 18, 2007 7:06 pm 
Regular
Regular

Joined: Fri Jan 20, 2006 7:45 pm
Posts: 97
Location: San Antonio, TX
I ran across this on Fowler's site:
http://martinfowler.com/eaaCatalog/repository.html

That should help clear things a bit. The basic description is thus:
Quote:
Mediates between the domain and data mapping layers using a collection-like interface for accessing domain objects.

My Respository does look like this, but my underlying DAO certainly does not.

Hope that helps!

_________________
Dum spiro, spero
-------------------------------
Rate my post if it helps...


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 18, 2007 7:09 pm 
Regular
Regular

Joined: Fri Jan 20, 2006 7:45 pm
Posts: 97
Location: San Antonio, TX
Oh, and I meant to point this out too:
Quote:
A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection.

Which my repository does, but I still have misgivings about some of my implementation details.

It will probably take a few more tries before I come up with something that I'm really excited about.

_________________
Dum spiro, spero
-------------------------------
Rate my post if it helps...


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 14 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.