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.  [ 10 posts ] 
Author Message
 Post subject: Generic IList and Data Source Assistant VisualStudio 2005
PostPosted: Wed Jun 28, 2006 6:07 am 
Newbie

Joined: Wed Jun 28, 2006 5:40 am
Posts: 1
Hello Everbody,

I just performed an upgrade to NHibernate 1.2.0 because of the new features regarding Generics (.NET 2.0). I try to set up a new small tutorial application with Visual Studio .NET 2005. To keep things simple for the students I want to use the visual Data Binding features that are new in this version of Visual Studio. I want to set up a new data source based on an object, mapped by NHibernate. This object includes simple attributes (long, string), a one-to-one mapping and a one-to-many-mapping configured as list.
The wizard creates the new data source based on this object, showing the simple attributes, the reference object and the list. But, the list is not being recognized as a store of objects of a specific class and therefore the hierarchy tree is not completed.
I switched to the new IList<T> feature of .NET 2.0 and it's working with the new NHibernate version. But the wizard still doesn't resolve the objects inside the IList<T>. I created a custom interface based on IList<T> and added the non Generic Version IList, then it works (interface test : IList<T>, IList)! The wizard works differently between IList<T> and IList.

I think it would be really great if new developers could perform their data binding visually on NHibernate persisted objects. Does anyone have a clue how to use NHibernate collections with the wizard? And if it is not possible right now, is the feature of a custom NHibernate IList<T> interface (similiar to the custom ISet and HashedSet) something realistic for the 1.2.0 version? It would be a great deal of advantage compared to Java/Swing development.

Hope to hear from you soon ...


NHibernate version: 1.2.0-Alpha
Name and version of the database you are using: MySQL 5.0

_________________
Regards,

Braunwald


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jun 28, 2006 6:46 am 
Newbie

Joined: Sun Sep 25, 2005 9:11 am
Posts: 13
Location: Bergen, Norway
It's possible to use the types in NHibernate.Collection.Generic in your classes, but I don't like that my objects must be aware of NHibernate.

I wish there could be a single interface in a seperate assembly that would implement both IList and IList<T>, and have the generic collections in NHibernate implement this interface. That way, my objects only have to rely on a single interface that easily could be used with other ORM-tools or mock objects.


Top
 Profile  
 
 Post subject: (long-ish) reply about the datasources window and IList<T
PostPosted: Wed Jun 28, 2006 7:49 am 
Beginner
Beginner

Joined: Wed Aug 10, 2005 6:21 pm
Posts: 24
Location: Antwerp, Belgium
devolish wrote:
It's possible to use the types in NHibernate.Collection.Generic in your classes, but I don't like that my objects must be aware of NHibernate.


My thoughts exactly. And while I haven't actually tried using NHibernate collection types in my business classes (yuck) I'm quite sure it would not solve the "problem" at hand.

devolish wrote:
I wish there could be a single interface in a seperate assembly that would implement both IList and IList<T>, and have the generic collections in NHibernate implement this interface. That way, my objects only have to rely on a single interface that easily could be used with other ORM-tools or mock objects.


I think that additionally implementing IList would not solve the problem.
If IList by itself is not enough to make it work and if IList<T> by itself is not enough to make it work (according to the OP and I noticed this myself too just yesterday) then implementing them both isn't going to make things work either, IMHO.

I was getting by (while waiting for the "generics" version of NH, expecting IList<T> to "enable" the data sources window) by temporarily adding a "strongly typed" version of every IList property in my (NHibernate-unaware) business objects like this:

Code:
    Private _items As IList
    Public Overridable Property Items() As IList
        Get
            If _items Is Nothing Then _items = New ArrayList()
            Return _items
        End Get
        Set(ByVal value As IList)
            If value IsNot _items Then
                _items = value
            End If
        End Set
    End Property

    Public Overridable ReadOnly Property ItemsST() As Generic.IList(Of ProjectItem)
        Get
            Return New IListWrapper(Of ProjectItem)(Me.Items())
        End Get
    End Property


This way, the data sources window worked the way I wanted it and all was great ! I was just waiting for the "generics" version of NH to be released so I could eliminate the "ST" (strongly typed) version of my IList properties.

The IListWrapper was something I cobbled together from information I found in Brian Noyes' book on databinding and probably from some example code that did something similar. I'm willing to post the code for it if it should interest anyone but really the only thing it does is wrap an IList and implement IList<T>, IList and ITypedList !!! Judging from the description of this interface in the databinding book I'm thinking the latter might be key to get the data sources window working although I can't seem to find anything about this in the documentation.

Anyway, I still have to investigate this further but I'm dying to hear what others think before I (maybe unnecessarily) waste my time with this.


Top
 Profile  
 
 Post subject: Re: (long-ish) reply about the datasources window and IList&
PostPosted: Wed Jun 28, 2006 8:16 am 
Newbie

Joined: Sun Sep 25, 2005 9:11 am
Posts: 13
Location: Bergen, Norway
desfen wrote:
I think that additionally implementing IList would not solve the problem.
If IList by itself is not enough to make it work and if IList<T> by itself is not enough to make it work (according to the OP and I noticed this myself too just yesterday) then implementing them both isn't going to make things work either, IMHO.


PersistentGenericList<T> and PersistentGenericBag<T> implements both IList and IList<T>, and because of that, using those types directly in my objects would make the collections show correctly in Visual Studio 2005.

Try it your self:

Code:
public class Customer
    {
        private IList<Invoice> invoices1;

        public IList<Invoice> Invoices1
        {
            get { return invoices1; }
            set { invoices1 = value; }
        }

        private ITest<Invoice> invoices2;

        public ITest<Invoice> Invoices2
        {
            get { return invoices2; }
            set { invoices2 = value; }
        }
    }

    public class Invoice
    {
        private Customer customer;

        public Customer Customer
        {
            get { return customer; }
            set { customer = value; }
        }
    }

    public interface ITest<T> : IList<T>, IList
    {
    }


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 29, 2006 5:18 am 
Beginner
Beginner

Joined: Wed Aug 10, 2005 6:21 pm
Posts: 24
Location: Antwerp, Belgium
Yes, you're right devolish. I tried it and now the VS2005 Data Sources window correctly handles the collections. That 'll teach me to open my big mouth without actually trying it first. :-(

Still doesn't make any sense to me though. Why couldn't MS have just done it right in VS2005 and make the Data Sources window work with either IList or IList<T> ?

Moreover, we're not out of the woods yet with the approach you suggested (i.e. explicitly defining an interface that just inherits from both IList<T> and IList for use in your business objects' collection properties).

I get loads of compiler errors in my business logic code about ambiguous methods and properties since the compiler doesn't know which Count property to access (IList<T>'s version or IList's). And that's just Count. Item, Add and many others give the same problem. So this approach still has usability problems, IMHO.

I think I'm gonna go back to using IListWrapper and always return it from my business object's collection properties. This adds overhead but it's quite small and it makes everything just work as expected.

Still feels dirty though ;-)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 29, 2006 9:32 am 
Newbie

Joined: Mon Jun 26, 2006 12:27 pm
Posts: 16
Here's what I've done which may or may not help you and may or may not be the best way to do it. My goals were two fold: one to loosely couple things so that I could replace the underlying components if I wanted to (including replacing NHibernate), and, two, trying to make Visual Studio 2005 happy so that I didn't have to fight things to get them to work and I could take advantage of it's data mapping abilities.

I basically created a data access assembly that wraps NHibernate. It exposes a data access interface that includes the normal stuff like:
Code:
public virtual void Save(object o);
public virtual IList<T> GetAll<T>();
public virtual T Get<T>();

and so on.

Anyway, you get the idea. In the data access assembly, there is an actual NHibernate implementation that implements the NHibernate specific stuff. This would allow me to swap out NHibernate if I wanted to for another mapper if I wanted to as long as I could maintain the interface which is pretty generic for a mapping tool.

Then, for the business class, I created a data access class with methods like:
Code:
public IList<BusinessObject> GetBusinessObjects()
{ .. }
public BusinessObject GetBusinessObject(object id)
{ .. }


The data access classes have very little code because all they really do is pass the call to an instance of the data access interface that they got from the data access factory, meaning they don't do anything NHibernate specific, and the underlying instance of the interface is what actually knows how to call NHibernate correctly. In that sense, I'm happy because no code outside the data access class knows about NHibernate (with the exception of the mapping xml files) and nothing is bound to an NHibernate specific interface or method.

VS is happy because the business layer data access classes provide all the strongly typed information that it likes. Sure, it's a little extra effort but it takes less than 5 minutes to code up the business data access layter. All you do is define the strongly typed methods and then pass all the calls to the generic data access interface. Let me know if you would like a better explanation or anybody has any better ideas.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 29, 2006 5:01 pm 
Beginner
Beginner

Joined: Wed Aug 10, 2005 6:21 pm
Posts: 24
Location: Antwerp, Belgium
Hi sclough, thanks for showing us your ideas. The way I've organised things is somewhat similar to yours, up to a point.

I too have isolated the objects in my Business Logic Layer ("BLL") from NHibernate by using interfaces. The difference is that I have just carbon-copied the SessionFactory, Session and Transaction classes into abstract interfaces (ISessionFactory, ISession and ITransaction resp.)

I could have defined these in a separate assembly but instead I chose to define them inside the BLL assembly once I realised that the BLL and this interface assembly would be closely coupled anyway. As an added bonus my business objects can now easily fetch/store data themselves during the course of their calculations, should the need arise. I don't expect this to be a common occurrence but you never know.

So, although it defines the persistence interfaces, my business layer doesn't contain a single line of persistence code. Like you I have a wrapper assembly which uses NHibernate itself to provide an implementation for the 3 aforementioned interfaces. It is up to client code (UI typically) to link them together to get things working. E.g. a BLL client typically does this:

Code:
BLL.Persistence.SessionFactory = New NHibernatePersistence.SessionFactory(connectionString)


where BLL.Persistence can be thought of as a ISessionFactory singleton in the BLL assembly and NHibernatePersistence.SessionFactory is the wrapper class inside the NHibernatePersistence assembly which implements ISessionFactory with the help of NHibernate itself.

All business objects inside BLL and all other objects who have access to the BLL namespace can now use BLL.Persistence.SessionFactory.OpenSession() to acquire a BLL.ISession object and start fetching/storing objects from/to the database using its methods, which are almost the exact same as those of NHibernate's Session object.

Conceptually all of this is 3-layer but I'll admit that for now I'm only using it in a 2-tier configuration (UI local + BLL local; DB remote) or even 1-tier when the DB connection is a SQLEXPRESS local connection. I hope it will remain standing when we start using it in a more service oriented architecture (e.g. WPF smart client + webservice + DB)

My hopes are high, which is typical when experience is low :-)))



Anyway, to get back on-topic: I have decided to stay with IList<T> in my business objects' collection properties and make more use of BindingSource components at the UI level (inside VS2005) to upgrade my IList<T> collections to IBindingList<T>, which is known to be ideal for both design-time and run-time databinding. I bind the BindingSource objects themselves to a BLL class at design-time and re-bind them to the actual BLL objects' collection properties at run-time to get what I want, so it's a slightly bigger hassle for the UI code but I think it's worth it.

Why? Because this way my BLL objects' properties remain unpolluted with fluff that's only needed because of UI idiosynchrasies (i.e. Winforms run-time and Visual Studio design-time databinding)

Sigh, I really need to learn to shorten my posts. Nobody's gonna read them...


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 30, 2006 11:25 am 
Newbie

Joined: Mon Jun 26, 2006 12:27 pm
Posts: 16
Well, I actually read your post :^).

It's similar. One difference is that I tried to model my interfaces in a more generic way in case I wanted to use the WORM or another mapper. In some cases, I'm sure I'll have to do some things to expose specific NHibernate functionality.

One thing is that you mentioned your design is so that the BLL objects can save themselves. I my case, they could save themselves as well if they wish to. I'm handling the factory and session creation completely behind the curtains, so if you get an IDataAccess implementation and call, say, Save(object), then the implementation checks to make sure it has a valid session and it gets that from a singleton which will create the session if necessary. Once it has a session, it stays active unless to call a Close() on the data access object.

In this way, client code does nothing except call a Save method for a particular object. It does not have to setup anything, the data access layer will initialize itself if necessary. If this is confusing, I could explain it in more depth.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jun 30, 2006 3:23 pm 
Beginner
Beginner

Joined: Wed Aug 10, 2005 6:21 pm
Posts: 24
Location: Antwerp, Belgium
sclough wrote:
Well, I actually read your post :^).

It's similar. One difference is that I tried to model my interfaces in a more generic way in case I wanted to use the WORM or another mapper.


Cool. I read yours too. We have company. If a third person also reads them we'll have a crowd :-))
Anyway, I agree. My approach might be harder to adapt to another ORM, if it ever comes to that.

sclough wrote:
One thing is that you mentioned your design is so that the BLL objects can save themselves.


Well, yes they could but that's not my intention. The main intended use for this is allowing business objects to consult other (unloaded) business objects during the course of their business calculations, for instance when calculating a bill of materials for an order. They could also write data to the db but I intend not to do that. IMHO that kind of thing is always up to the UI (or a controller in an MVC scenario).

sclough wrote:
I'm handling the factory and session creation completely behind the curtains, so if you get an IDataAccess implementation and call, say, Save(object), then the implementation checks to make sure it has a valid session and it gets that from a singleton which will create the session if necessary. Once it has a session, it stays active unless to call a Close() on the data access object.


I see what you mean. I have seen several threads in these forums discussing these very same 2 options:

1. I have chosen to let (parts of) my UI code consciously manage db-sessions and transactions, because I'm afraid performance might suffer if I don't exactly control everything. I feel I need to understand as much as possible about when and why NHibernate talks to the database on my behalf. In the meanwhile, I'm hoping that the semantics of NHibernate's API are similar to (or more complicated than) other ORMs' APIs, so that switching to another ORM will not force me to rewrite big parts of my UI or BLL code.

2. You have chosen to conceal these low-level complexities which will greatly simplify your UI code and also isolate it from the low-level specific nitty-gritty. Doing that will indeed allow you to easily switch away from NHibernate in the future but I think you might run into inexplicable bugs and performance problems later down the road because you or your clients have no way to control what's really happening under the hood.

That being said, I'm no expert (yet). One thing is for sure: both approaches have their pros and cons. Thanks for sharing your ideas. I enjoyed it :-)


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 05, 2006 8:28 am 
Newbie

Joined: Mon Jun 26, 2006 12:27 pm
Posts: 16
I think you have some good observations. One thing I have recently done is provide a base abstract class for all the data access objects for the business layer and it provides some basic plumbing, but also exposes some things. For example, it exposes the underlying IDataAccess interface being used. This allows you to control things such as start or stop a transaction on the access object being used, close the access object which will terminate your session and connection, access the underlying database connection if you need to do something custom, etc. In addition, you can pass a specific IDataAccess instance to the DAL class and then it will use that one rather then get it's own from the singleton when you call a method like Save() or whatever.

I sympathize greatly with your desire for control and performance. In fact, one of my big complains with Microsoft's approach is that they try to hide too much under the curtains and you end up nor really knowing what they are doing and with potential bloat. I'm striving for a balance where if I just want to save something and get a few objects the underlying implementation knows how to instantiate itself and make things work, but at the same time it exposes enough of itself to the outside world that I can control it if I want to. For example, the Singleton to create a session and all that are public classes so I can configure and manipulate them outside of DAL code if I want to, or I can just call the DAL object and it will realize that nobody has setup the session and load that and make things work.

In the end, I'm always interested to see other people's implementations and hear their thoughts. I don't consider my way the best necessarily as I'm constantly learning and some patterns I used in the past I now realize are not the best and my techniques have certainly changed over time.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 10 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.