-->
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: Strongly Typed Collections with C# Generics
PostPosted: Fri May 13, 2005 2:02 pm 
Newbie

Joined: Fri May 13, 2005 1:59 pm
Posts: 11
I was hoping to get some feedback on my approach to supporting strongly typed collections in a persistable class.

This example uses three tables: (1) Party, (2) PartyRole and (3) RoleType. PartyRole is a join table with a composite ID of PartyId and RoleTypeId. Here's the collection mapping:

Code:
<class name="Party" table="Party">
    <id name="Id" column="PartyId" unsaved-value="0">
        <generator class="identity" />
    </id>
    <set name="RolesUntyped" table="PartyRole" cascade="all">
        <key column="PartyId" />
        <many-to-many class="RoleType" column="RoleTypeId" outer-join="auto" />
    </set>
</class>


The RolesUntyped property is implemented in the Party class as:

Code:
private Iesi.Collections.ISet RolesUntyped
{
    get { return new HybridSet(_roles); }

    set 
    {
        _roles.Clear();
        foreach (object o in value) _roles.Add(o as RoleType);
    }
}


Note that RolesUntyped is a private property with a getter and a setter. There's a corresponding public property defined as:

Code:
public List<RoleType> Roles
{
    get { return _roles; }
}


Lastly, the corresponding member field is defined as:

Code:
private List<RoleType> _roles = new List<RoleType>();


This let's me leverage NHibernate for persistence while getting the advantages of strongly typed collection syntax. Let me know what you think.


Top
 Profile  
 
 Post subject:
PostPosted: Fri May 13, 2005 2:22 pm 
Contributor
Contributor

Joined: Wed May 11, 2005 4:59 pm
Posts: 1766
Location: Prague, Czech Republic
This will probably cause inefficent set updates (whole collection will be deleted and re-created), unless it's mapped with inverse="true" (and contains entities).


Top
 Profile  
 
 Post subject:
PostPosted: Mon May 16, 2005 10:48 am 
Newbie

Joined: Fri May 13, 2005 1:59 pm
Posts: 11
Thanks, Sergey. The collection does contain entities, so it should just be copying references from one collection to the other. In this particular case, the assocation is one-way, so is it still useful to set inverse="true"?

Are their plans to provide native support for System.Collections.Generics in a future version of NHibernate? Wintellect's PowerCollections class library has generic-based implementations of ordered and unordered sets as well as other useful collection types.

http://www.wintellect.com/powercollections/


Top
 Profile  
 
 Post subject: PersistentCollectionFactory
PostPosted: Thu May 19, 2005 8:36 am 
Hi!
Recently there has been a discussion in the mailing list where developers shared their ideas about .net 2.0 especially about supporting generics. One idea was that NHibernate could provide a PersistentCollectionFactory. Is this still under consideration?

thomas


Top
  
 
 Post subject:
PostPosted: Thu May 19, 2005 2:41 pm 
Contributor
Contributor

Joined: Wed May 11, 2005 4:59 pm
Posts: 1766
Location: Prague, Czech Republic
Tufelix wrote:
One idea was that NHibernate could provide a PersistentCollectionFactory. Is this still under consideration?

It is, and probably will be under consideration for a long time. We are not yet brave enough to diverge much from the original Hibernate code and don't have much time. So unless somebody thinks up a solution, implements it, and sends us a patch (with tests!), it will stay unsolved for a long time :-(


Top
 Profile  
 
 Post subject: Re: Strongly Typed Collections with C# Generics
PostPosted: Thu Jul 07, 2005 5:44 am 
Hi Jim

Have you experimented more with this? Anyone else?

We to have tried doing this, and we have several approaches. On which is almost exactly like yours.

The problem with this approach is that it will not work with lazy load, because the loop through the untyped collection will cause the collection to be fetched from the database.

Therefore we tried with something like this:

Code:
private System.Collections.IList CustomerUntypedList
{
    get { return (System.Collections.IList) _customerTypedList; }
    set { _customerTypedList = (IList<Customer>) value; } // This fails with: "Unable to cast object of type 'NHibernate.Collection.Bag' to type 'System.Collections.Generic.IList`1'."

}

private System.Collections.Generic.IList<Customer> _customerTypedList;
public System.Collections.Generic.IList<Customer> CustomerTypedList
{
    get { return _customerTypedList; }
}


Does anyone know if it is possible to cast a IList like the NHibernate Bag to a Generic list, or will this always fail? Please notice that the above code compiles.

Thomas


Top
  
 
 Post subject:
PostPosted: Thu Jul 07, 2005 8:51 pm 
Regular
Regular

Joined: Mon May 16, 2005 1:35 am
Posts: 67
The issue with casting an IList<T> to an IList is that IList<T> does not derive from IList. However, IEnumerable<T> DOES inherit from IEnumerable, which means in the case of IEnumerable<T>, casting back to IEnumerable IS possible - not that that helps us much here.

One solution you could try if you want to take advantage of generics in .NET 2.0 before the NHibernate code is updated, is to create a ListAdapter<T> class, which accepts an IList in its constructor and provides a type-safe wrapper around the IList implementation passed to its constructor.

You would then have one of your private member fields typed as IList (which you would point NHibernate at using the "field" access strategy), and another private member field typed as ListAdapter<T> which would be publicly available via a getter/setter.

I imagine the private ListAdapter<T> member would need to be lazy initialized when the getter is accessed. It could not be initialized in the constructor as NHibernate would not have had an opportunity to set the private IList member it wraps at this point.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 08, 2005 12:24 pm 
Newbie

Joined: Fri May 13, 2005 1:59 pm
Posts: 11
I'm now using Wintellect's PowerCollections to solve the problem. I declare a member as NHibernate.Collection.Set then cast it to a typed ICollection, e.g.:

Code:
public System.Collections.Generic.ICollection<RoleType> Roles
{
   get
   {
      return Algorithms.TypedAs<RoleType>(_roles);
   }
}


Note that the resulting collection is read-only.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 20, 2005 9:18 pm 
I did something very similar to the code in the first post for a bag collection, but found my version didn't work...

Code:
private List<Category> _categories;

public List<Category> Categories
{
    get { return _categories; }
    set { _categories = value; }
}

public IList CategoriesNHibernate
{
    get { return _categories; }
    set
    {
        _categories.Clear();

        foreach (Category category in value)
            _categories.Add(category);
    }
}


List<Category> satisfies IList, so I can just return _categories to NHibernate as is. (This turned out to be a crucial difference... I was returning my actual collection to NHibernate instead of a copy like the code in the first post did.)

The problem arose from the documented fact that NHibernate replaces CategoryNHibernate with its own collection class during a save or update, in this case NHibernate.Collection.Bag. What I didn't know was this was actually a wrapper around the collection class I returned to NHibernate. So when I called _categories.Clear(), I was actually clearing out value (NHibernate.Collection.Bag) as well, and deleting all my categories... (The foreach loop never found anything in value to add.)

Note, this only happened in a save or update -- the retrieval of the object from the datastore works just fine, since value (NHibernate.Collection.Bag) in that case is not a wrapper but rather a new collection altogether.

If you want to do something similar, for bag at least, this modification solves the problem...

Code:
public IList CategoriesNHibernate
{
    get { return _categories; }
    set
    {
        List<Category> list = new List<Category>();

        foreach (Category category in value)
            list.Add(category);

        _categories = list;
    }
}


Or you can do what the code in the first post did and return a copy of the collection to NHibernate...

Code:
public IList CategoriesNHibernate
{
    get { return new ArrayList(_categories); }
    set
    {
        _categories.Clear();

        foreach (Category category in value)
            _categories.Add(category);
    }
}


Top
  
 
 Post subject:
PostPosted: Fri Oct 21, 2005 7:40 am 
Contributor
Contributor

Joined: Sat Sep 24, 2005 11:25 am
Posts: 198
Try this:

http://www.ayende.com/projects/nhiberna ... erics.aspx

It'll let you use generic collections (and some other goodies)


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.