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.  [ 18 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Cannot bind DataGridView to an empty collection
PostPosted: Wed Aug 04, 2010 4:09 am 
Newbie

Joined: Wed Aug 04, 2010 3:58 am
Posts: 12
The last 3 weeks I have experienced many problems with the DataGridView. I'm using NHibernate 2.1.2 to retrieve objects from a database and I use the DataGridView to represent this data in a structured way. I've been able to isolate the problem in a test-case.

So here's the test-case:
I have an object called Person. This Person has a collection of PersonCars. A PersonCar consists out of a CarType and a Registration Number. Very basic so far since it's a test-case anyway :)

When I retrieve a Person from the database with already existing PersonCars I can add new values to the DataGridView just fine. I created a test-button in the test-case form to print the values bound to the DataGridView into a textual representation. This works perfectly and I see the values I have entered.

So here comes the weird part. When I retrieve an object WITHOUT any PersonCars (Count == 0) I can add as many PersonCars as I like (just what you would expect). However when I start printing the values bound to the DataGridView they don't match. All the objects in the PersonCars collection are uninitialized. They aren't NULL but the values are default values. So it looks like the DataGridView isn't updating the values back into the correct objects.

You can download the test-case here:
http://home.planet.nl/~lyckl022/temp/Em ... roblem.zip

Below are the steps you need to perform to see the result for your self:

STEP 1: Select the first Person in the left DataGridView (should already be selected when you open the form).
STEP 2: Select add as many PersonCars in the right DataGridView as you like.
STEP 3: Click the button in the right bottom corner to see the values in the right DataGridView being shown in a textual representation. The values should be the same as what you entered.

STEP 4: Select the second Person in the left DataGridView.
STEP 5: Select add as many PersonCars in the right DataGridView as you like.
STEP 6: Click the button in the right bottom corner to see the values in the right DataGridView being shown in a textual representation. As you now hopefully see, the values do NOT match with what you have entered. In fact the whole object looks like it has just been initialized and never bound correctly to the DataGridView.

There is a simple "fix" for this problem though:

Code:
public IList<PersonCar> Cars {
   get {
      if (this.cars.Count == 0)
         this.cars = new List<PersonCar>();
      return this.cars;
   }
}


Just set the instance of the cars variable to a new List<PersonCar>() whenever you call the Cars property. However this way you won't be able to persist the data because the following error will occur if you do so:

Quote:
A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: <Type Of Class>


I'm running out of idea's... I really really hope someone can help me out!


Top
 Profile  
 
 Post subject: Re: Cannot bind DataGridView to an empty collection
PostPosted: Wed Aug 04, 2010 8:45 am 
Newbie

Joined: Wed Aug 04, 2010 8:09 am
Posts: 3
Well,

When you are creating an object to represent your collection, you run into this problem. This happens because the NHibernate engine instances a PersistentGenericList for your collection and, in the Cars get field, it is changed to the List<PersonCar>() object and then NHibernate loses the management to it. Thus, to make your list behave like expected with the DataGridView, it needs to be an IBindingList instance to properly answer to the GUI events.

Since yesterday I'm focused in solving this sort of problem just because I'm running into the same issue. It's not that easy to do this as we need to create a custom collection that implements IUserCollectionType and IBindingList properly. Yes, it's a little bit tricky!

Does anybody here knows the existence of such custom collection? Please help us!


Top
 Profile  
 
 Post subject: Re: Cannot bind DataGridView to an empty collection
PostPosted: Wed Aug 04, 2010 9:16 am 
Newbie

Joined: Wed Aug 04, 2010 3:58 am
Posts: 12
teonivalois wrote:
When you are creating an object to represent your collection, you run into this problem. This happens because the NHibernate engine instances a PersistentGenericList for your collection and, in the Cars get field, it is changed to the List<PersonCar>() object and then NHibernate loses the management to it.


Yes, I completely understand. The "fix" was just a hack to figure out the cause of the DataGridView not being able to bind the data correctly.

teonivalois wrote:
Thus, to make your list behave like expected with the DataGridView, it needs to be an IBindingList instance to properly answer to the GUI events.


I see... What I'm wondering, if you use the BindingSource as your DataSource, doesn't it automatically create some sort of Proxy around your IList?

teonivalois wrote:
Since yesterday I'm focused in solving this sort of problem just because I'm running into the same issue. It's not that easy to do this as we need to create a custom collection that implements IUserCollectionType and IBindingList properly. Yes, it's a little bit tricky!

Does anybody here knows the existence of such custom collection? Please help us!


It's great to read that I'm not alone with this issue :-)

I have 2 options left that I need to check tonight (hopefully one of these will fix this issue). I will also try your suggestion with the IBindingList. Might come up with a generic solution for this problem.

It would be great if you can keep me updated about your progress.


Top
 Profile  
 
 Post subject: Re: Cannot bind DataGridView to an empty collection
PostPosted: Wed Aug 04, 2010 4:40 pm 
Newbie

Joined: Wed Aug 04, 2010 3:58 am
Posts: 12
I implemented the IEditableObject interface and I can say that all the calls are correctly being made (BeginEdit, CancelEdit and EndEdit). Something interesting happened though. I wrote several info to the output window with Debug.WriteLine(""). Whenever the collection is empty, the values will always be set to default values. So for a string it will be "", for an int it will be 0, etc. So now for the interesting part. Once I added the values, the values will not be bound correctly. However when I call ResetBindings(true) on the BindingSource, the values will be reset to what they are now. So the values in the DataGridView disappear since they have never been set correctly to the bound object in the first place. If you now change anything in the DataGridView it WILL be saved correctly.

So what changed?? I have no idea and I think the only way to find out is to dig into the PersistentGenericBag. I'll dive into that tomorrow.


Top
 Profile  
 
 Post subject: Re: Cannot bind DataGridView to an empty collection
PostPosted: Sat Aug 14, 2010 4:31 pm 
Newbie

Joined: Wed Aug 04, 2010 3:58 am
Posts: 12
I don't understand why we are the only two having this problem. Can anyone point us in the right direction? I've debugged within the NHibernate source code but I have no idea why it isn't working the way it should work. I think I have provided the most basic sample possible and there must be others who experience the same problem. If anyone of you guys could have a look at the provided example I will be very thankful!


Top
 Profile  
 
 Post subject: Re: Cannot bind DataGridView to an empty collection
PostPosted: Sat Aug 14, 2010 4:40 pm 
Newbie

Joined: Wed Aug 04, 2010 8:09 am
Posts: 3
Hi,

I solved my problem setting the DataGridView datasource as a BindingSource, then setting my Collection to the BindingSource's Datasource property. So i can still have my simple List<T>.

Hope it helps!


Top
 Profile  
 
 Post subject: Re: Cannot bind DataGridView to an empty collection
PostPosted: Sun Aug 15, 2010 4:38 am 
Newbie

Joined: Wed Aug 04, 2010 3:58 am
Posts: 12
Hi,

I think I'm already doing that.

Code:
BindingSource bindingSource = new BindingSource();
bindingSource.DataSource = person.Cars; // Cars being an IList<Car>
dataGridView.DataSource = bindingSource;


Is this how you do it? Because this doesn't work here.

Can you possibly extract your code into a simple test project so I can look
for differences between how we both bind to the DataGridView?


Top
 Profile  
 
 Post subject: Re: Cannot bind DataGridView to an empty collection
PostPosted: Sun Aug 15, 2010 10:39 am 
Newbie

Joined: Wed Aug 04, 2010 8:09 am
Posts: 3
Are you refreshing the bindingsource's datasource at every change in your list?


Top
 Profile  
 
 Post subject: Re: Cannot bind DataGridView to an empty collection
PostPosted: Sun Aug 15, 2010 1:38 pm 
Newbie

Joined: Wed Aug 04, 2010 3:58 am
Posts: 12
teonivalois wrote:
Are you refreshing the bindingsource's datasource at every change in your list?


I do not since I let the handling over to the DataGridView. I did create a test button on my form. It programmatically adds a new object to the collection and refreshes the BindingSource. Even if I programmatically set the values of this object, they will not be visible in the DataGridView.

I think I made an important discovery though. I did some extensive testing and found something interesting. It seems that the DataGridViewTextBoxColumn will not correctly binds itself when binding an empty PersistentGenericBag<T>. I noticed a few things.

The IsDataBound property of the DataGridViewTextBoxColumn is:
1). FALSE when bound to the empty PersistentGenericBag<T>
2). TRUE when bound to a new instance of List<T>
3). TRUE when bound to a non-empty PersistentGenericBag<T>

If I remove all the columns in the DataGridView and set AutoGenerateColumns to TRUE:
4). It will have NO columns when binding to an empty PersistentGenericBag<T>.
5). It will have ALL the columns when binding to an empty List<T>
6). It will have ALL the columns when binding to a non-empty PersistentGenericBag<T>.

I believe this perfectly explains the behavior I'm seeing. It makes sense to me that the DataGridView can never correctly update itself if it has not been correctly bound to a datasource.

Does anyone have an idea what might go wrong here? What could be the reason that IsDataBound returns FALSE for an empty PersistentGenericBag<T>?


Top
 Profile  
 
 Post subject: Re: Cannot bind DataGridView to an empty collection
PostPosted: Sun Aug 22, 2010 2:46 pm 
Newbie

Joined: Wed Aug 04, 2010 3:58 am
Posts: 12
I've made a custom implementation of the GenericPersistentBag<T>. Loading data isn't fully working yet because I'll have to dive into the inner workings of NHibernate first. However creating a new record in the left grid and adding new records to the right grid does work now. It databounds correctly and works the way I expected it to work.

It looks like there is some kind of bug in the GenericPersistentBag<T>. I've spend so much time on this issue already and I don't like the idea of me writing a custom implementation based on the GenericPersistentBag. I'm a bit suprised by the lack of response here. I think I'll have to ditch NHibernate and find something else because I can spend another month searching for an answer and I don't know whether this will be the last problem I'll encounter. The lack of response tells me that I'm basically all alone on issues I might encounter.

If the devs want my code of the GenericPersistentBag they can send me a PM. Thanks teonivalois for your time but I'm gonna stop here and find an alternative.


Top
 Profile  
 
 Post subject: Re: Cannot bind DataGridView to an empty collection
PostPosted: Mon Aug 23, 2010 3:11 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
I assume the problem is that hibernate does not initialize your list when there are no objects in the database. In that case your list is null and the grid can't bind to it. What you should do is this:

Code:
private        IList<Person> cars = new List<PersonCar>();

public IList<PersonCar> Cars {
   get {
      return this.cars;
   }
}

_________________
--Wolfgang


Top
 Profile  
 
 Post subject: Re: Cannot bind DataGridView to an empty collection
PostPosted: Tue Aug 24, 2010 3:32 am 
Newbie

Joined: Wed Aug 04, 2010 3:58 am
Posts: 12
wolli wrote:
I assume the problem is that hibernate does not initialize your list when there are no objects in the database. In that case your list is null and the grid can't bind to it. What you should do is this:

Code:
private        IList<Person> cars = new List<PersonCar>();

public IList<PersonCar> Cars {
   get {
      return this.cars;
   }
}


That's the first things I did and it didn't work. What did work was changing value to value.ToList(); But you will never be able to persist it back because NHibernate detects that it isn't a PersistentGenericBag<T> anymore.

Code:
IList<PersonCar> cars = new List<PersonCar>();
public virtual IList<PersonCar> Cars {
   get {
      return cars;
   }
   set {
      cars = value.ToList();
   }
}


So that means there's something wrong in the PersistentGenericBag<T> or more likely the AbstractPersistentCollection that's being used in the PersistentBag. I made a custom bag implementation based on only the IList and IPersistentCollection and I didn't had any of these problems. I couldn't load data yet but whenever I added data it did so correctly.


Top
 Profile  
 
 Post subject: Re: Cannot bind DataGridView to an empty collection
PostPosted: Tue Aug 24, 2010 4:01 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
I found at least one error in your mapping. I'm not sure if that's the source of your problem, but it's worth a try:

Code:
<bag name="Cars" table="PersonCars" cascade="all-delete-orphan" lazy="false" inverse="true" order-by="RegistrationNumber desc">
      <key column="ID" />
      <one-to-many class="PersonCar" />
    </bag>


Your key column has to be PersonId not ID.

_________________
--Wolfgang


Top
 Profile  
 
 Post subject: Re: Cannot bind DataGridView to an empty collection
PostPosted: Tue Aug 24, 2010 5:49 am 
Newbie

Joined: Wed Aug 04, 2010 3:58 am
Posts: 12
wolli wrote:
Your key column has to be PersonId not ID.


Thanks a lot wolli. I've changed it to PersonID but the problem is still there. I don't see any difference in the loaded data though.


Top
 Profile  
 
 Post subject: Re: Cannot bind DataGridView to an empty collection
PostPosted: Tue Aug 24, 2010 7:59 am 
Expert
Expert

Joined: Thu Dec 14, 2006 5:57 am
Posts: 1185
Location: Zurich, Switzerland
Try this in frmMain.Initialize():

carsBindingSource.DataSource = typeof(PersonCar);

_________________
--Wolfgang


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 18 posts ]  Go to page 1, 2  Next

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.