-->
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.  [ 22 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Strongly Typed Collections
PostPosted: Sat Jun 02, 2007 9:48 pm 
Beginner
Beginner

Joined: Fri Jun 01, 2007 4:55 pm
Posts: 24
Hi All,

I have searched docs and online but can't see anyone who's posted about this requirement....

I have custom collections which inherit the collectionbase class. These handle adding and retrieving by some key value and then returns a typed object

Eg a collection of websiteTests:

Code:
Public Class WebsiteTests
        Inherits System.Collections.CollectionBase

        Public Sub New()
            mKeys = New Hashtable
        End Sub

        Private mKeys As New Hashtable

        Public Sub Add(ByVal Test As WM.Business.Interfaces.IWebsiteTest)
            If Not Test Is Nothing Then
                MyBase.List.Add(Test)
                mKeys.Add(Test.Name, MyBase.List.Count - 1)
            End If
        End Sub

        Default Public ReadOnly Property Item(ByVal TestName As String) As Interfaces.IWebsiteTest
            Get
                If mKeys.ContainsKey(TestName) Then
                    Dim Index As Integer = CType(mKeys.Item(TestName), Integer)
                    Return CType(MyBase.List.Item(Index), Interfaces.IWebsiteTest)
                Else
                    Return Nothing
                End If
            End Get
        End Property
        Default Public ReadOnly Property Item(ByVal Index As Integer) As Interfaces.IWebsiteTest
            Get
                Return CType(MyBase.List.Item(Index), Interfaces.IWebsiteTest)
            End Get
        End Property
    End Class


The structure i am trying to achieve is i have a class Website which has a collection of websiteTests. None of the NHibernate classes can set up my custom collections as i presume it is expecting an arraylist of some kind (intrinsic .net collection or something)

My Class for a website is this:
Code:
Public Class Website
        Implements Business.Interfaces.IWebsite

        Protected mWebsiteID As Integer = 0
        Protected mName As String = String.Empty
        Protected mdescription As String = String.Empty
        Protected mURL As String = String.Empty
        Protected mWebsiteTests As WM.Business.Collections.WebsiteTests

        Public Property WebsiteID() As Integer Implements Interfaces.IWebsite.WebsiteID
            Get
                Return mWebsiteID
            End Get
            Set(ByVal value As Integer)
                mWebsiteID = value
            End Set
        End Property

        Public Property Name() As String Implements Interfaces.IWebsite.DomainName
            Get
                Return mName
            End Get
            Set(ByVal value As String)
                mName = value
            End Set
        End Property

        Public Property description() As String Implements Interfaces.IWebsite.Description
            Get
                Return mdescription
            End Get
            Set(ByVal value As String)
                mdescription = value
            End Set
        End Property

        Public Property URL() As String Implements Interfaces.IWebsite.Path
            Get
                Return mURL
            End Get
            Set(ByVal value As String)
                mURL = value
            End Set
        End Property

        Public Property WebsiteTests() As Collections.WebsiteTests Implements Interfaces.IWebsite.WebsiteTests
            Get
                Return mWebsiteTests
            End Get
            Set(ByVal value As Collections.WebsiteTests)
                mWebsiteTests = value
            End Set
        End Property
    End Class

and my mapping file is:

Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
  <class name="WM.Business.Classes.Website, Business" table="Websites" >
    <id name="WebsiteID" column="WebsiteID" type="Int32" unsaved-value="0">
      <generator class="identity" />
    </id>
    <property name="Name" type="String" length="50">
      <column name="Name" unique-key="WebsiteNameUnique"></column>
    </property>

    <property name="description" column="description" type="String" length="200" />
    <property name="URL" column="URL" type="String" length="100" />
    <!--
    <set name="WebsiteTests" table="WebsiteTestWebsiteAssociation">
      <key column="WebsiteID" />
      <many-to-many column="WebsiteTestID" class="WM.Business.Classes.WebsiteTest, Business" />
    </set>-->
  </class>

</hibernate-mapping>



The bit that is commented out is what needs to be replaced to be able to meet the format of my custom collection. What should it be?

Many thanks


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jun 03, 2007 12:07 am 
Regular
Regular

Joined: Sun Jan 21, 2007 4:33 pm
Posts: 65
Now I remember why I hate VB.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jun 03, 2007 4:49 am 
Beginner
Beginner

Joined: Tue May 02, 2006 8:04 am
Posts: 34
Map your mWebsiteTests as IList and create a property that returns the list as your custom collection.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jun 03, 2007 5:23 am 
Beginner
Beginner

Joined: Fri Jun 01, 2007 4:55 pm
Posts: 24
.ben wrote:
Map your mWebsiteTests as IList and create a property that returns the list as your custom collection.


Ok, Im quite new to NHibernate, so let me see if I have understood correctly.

In the Websites class where i have an private property mwebsiteTest

Code:
Protected mWebsiteTests As WM.Business.Collections.WebsiteTests


Are you saying i should change this to

Code:
Protected mWebsiteTests As IList


Then get the NHibernate mapping file to populate the internal property so something like:

Code:
    <List name="mWebsiteTests" table="WebsiteTestWebsiteAssociation">
      <key column="WebsiteID" />
      <many-to-many column="WebsiteTestID" class="WM.Business.Classes.WebsiteTest, Business" />
    </list>-->


And if this is correct, then how do bridge the gap between the data in the mwebsiteTest to the collection class returned?


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jun 03, 2007 5:49 am 
Beginner
Beginner

Joined: Tue May 02, 2006 8:04 am
Posts: 34
Something like this perhaps:

Code:
Public Class WebsiteTests
    Inherits System.Collections.CollectionBase

    Private mList As IList(Of WM.Business.Interfaces.IWebsiteTest)

    Public Sub New()
        mKeys = New Hashtable
        mList = new List(Of WM.Business.Interfaces.IWebsiteTest)
    End Sub

    Public Sub New(ByVal tests As IList(Of WM.Business.Interfaces.IWebsiteTest))
        mList = tests
        mKeys = New Hashtable
        For Each test As WM.Business.Interfaces.IWebsiteTest In mList
            MyBase.List.Add(test)
            mKeys.Add(test.Name, MyBase.List.Count - 1)
        Next
    End Sub

    Private mKeys As New Hashtable

    Public Sub Add(ByVal Test As WM.Business.Interfaces.IWebsiteTest)
        If Not test Is Nothing Then
            MyBase.List.Add(test)
            mKeys.Add(Test.Name, MyBase.List.Count - 1)
            mList.Add(Test)
        End If
    End Sub

    Default Public ReadOnly Property Item(ByVal TestName As String) As Interfaces.IWebsiteTest
        Get
            If mKeys.ContainsKey(TestName) Then
                Dim Index As Integer = CType(mKeys.Item(TestName), Integer)
                Return CType(MyBase.List.Item(Index), Interfaces.IWebsiteTest)
            Else
                Return Nothing
            End If
        End Get
    End Property
    Default Public ReadOnly Property Item(ByVal Index As Integer) As Interfaces.IWebsiteTest
        Get
            Return CType(MyBase.List.Item(Index), Interfaces.IWebsiteTest)
        End Get
    End Property

End Class


And in your entity something like:
Code:
    Public ReadOnly Property Tests() As WebsiteTests
        Get
            Return New WebsiteTests(mWebsiteTests)
        End Get
    End Property


Btw, I know I said IList, but IList<T> is fine too ;).


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jun 03, 2007 6:35 am 
Beginner
Beginner

Joined: Fri Jun 01, 2007 4:55 pm
Posts: 24
Thanks, what would the mapping file look like?


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jun 03, 2007 7:01 am 
Beginner
Beginner

Joined: Tue May 02, 2006 8:04 am
Posts: 34
Like you posted it, but map to the field instead of the property. (access="field") and use bag instead of list. Unless you want the order of the items saved aswell


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jun 03, 2007 8:32 am 
Beginner
Beginner

Joined: Fri Jun 01, 2007 4:55 pm
Posts: 24
Ok I have copied the collection class as you wrote, and have the mapping as

Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
  <class name="WM.Business.Classes.Website, Business" table="Websites" >
    <id name="WebsiteID" column="WebsiteID" type="Int32" unsaved-value="0">
      <generator class="identity" />
    </id>
    <property name="Name" type="String" length="50">
      <column name="Name" unique-key="WebsiteNameUnique"></column>
    </property>

    <property name="description" column="description" type="String" length="200" />
    <property name="URL" column="URL" type="String" length="100" />
    <bag name="mWebsiteTests" table="WebsiteTestWebsiteAssociation" access="field">
      <key column="WebsiteID" />
      <many-to-many column="WebsiteTestID" class="WM.Business.Classes.WebsiteTest, Business" />
    </bag>
  </class>

</hibernate-mapping>


But I get a en error now when loading a list from this function

Code:
Public Function List() As WM.Business.Collections.Websites Implements WM.Business.Interfaces.DataAccess.IWebsiteDA.List
        Dim obj As New WM.Business.Classes.Website

        Dim Websites As System.Collections.IList
        Dim Result As New WM.Business.Collections.Websites
        Websites = MyBase.Session.CreateCriteria(obj.GetType).List()
        For Each Website As WM.Business.Interfaces.IWebsite In Websites
            Result.Add(Website)
        Next
        MyBase.EndSession(False)
        Return Result

    End Function


the error is:

{"The type NHibernate.Collection.Bag can not be assigned to a field of type System.Collections.Generic.IList`1[WM.Business.Interfaces.IWebsiteTest] setter of WM.Business.Classes.Website.mWebsiteTests"}

Now before i had the bag part of the mapping file - this worked ok.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jun 03, 2007 9:53 am 
Beginner
Beginner

Joined: Tue May 02, 2006 8:04 am
Posts: 34
Are you using NHibernate 1.2.0? If not use IList instead of the generic version.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Jun 03, 2007 9:59 am 
Beginner
Beginner

Joined: Fri Jun 01, 2007 4:55 pm
Posts: 24
i think it is 0.8.0 - which by your post probably means i should be upgrading to the latest NHibernate release? Since, i have not really started on the project as yet would makes sense to learn the latest version... Ill post back once I have done that


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 05, 2007 8:53 am 
Beginner
Beginner

Joined: Fri Jun 01, 2007 4:55 pm
Posts: 24
ok, I have upgraded to 1.2 but now my configuration files do not load. I have them compiled in (for now as i had issues with NUnit loading these values from an app.config file - ill work on this later)

Code:
Private Shared Sub LoadConfig()
        mConfiguration = New NHibernate.Cfg.Configuration
        mConfiguration.SetProperty("hibernate.connection.provider", "NHibernate.Connection.DriverConnectionProvider")
        mConfiguration.SetProperty("hibernate.connection.driver_class", "NHibernate.Driver.SqlClientDriver")
        mConfiguration.SetProperty("hibernate.connection.connection_string", "Server=(local);Database=WebsiteMonitor;User=sa;Pwd=123;")
        mConfiguration.SetProperty("hibernate.connection.isolation", "ReadCommitted")
        mConfiguration.SetProperty("hibernate.dialect", "NHibernate.Dialect.MsSql2000Dialect")
        mConfiguration.AddAssembly("NHDAL")
        mFactory = mConfiguration.BuildSessionFactory
    End Sub


The line that fails is the AddAssembly line with this error

{"Could not find schema information for the element 'urn:nhibernate-mapping-2.0:hibernate-mapping'."}

Do i need to change my mapping files for this version? I am a bit lost as to where to turn on this one

mapping file of the file that seemed to have the problem:
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0">
  <class name="WM.Business.Classes.WebsiteSettings, Business" table="WebsiteSettings" >
    <id name="WebsiteSettingID" column="WebsiteSettingID" type="Int32" unsaved-value="0">
      <generator class="identity" />
    </id>
    <property name="WebsiteID" column="WebsiteID" type="Int32" length="4" />
    <property name="CheckInterval" column="CheckInterval" type="Int32" length="4" />
    <property name="CheckPeriod" column="CheckPeriod" type="Int32" length="4" />
    <property name="NotificationDelaySupport" column="NotificationDelaySupport" type="Int32" length="4" />
    <property name="NotifactionDelayOwner" column="NotifactionDelayOwner" type="Int32" length="4" />
    <property name="NotificationDelayIO" column="NotificationDelayIO" type="Int32" length="4" />
  </class>

</hibernate-mapping>


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jun 05, 2007 10:37 am 
Contributor
Contributor

Joined: Wed May 11, 2005 4:59 pm
Posts: 1766
Location: Prague, Czech Republic
Please read the migration guide. The link is in the sticky announcement of 1.2.0.GA in this forum.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 07, 2007 11:41 am 
Beginner
Beginner

Joined: Fri Jun 01, 2007 4:55 pm
Posts: 24
Thanks, that did the trick (for that one!)

Then got some other errors which are in mapping files that im not using yet so have removed them for now, but am getting a few errors like this one

"The following types may not be used as proxies:
WM.Business.Classes.Contacts: method set_ContactID should be virtual
WM.Business.Classes.Contacts: method set_EmailAddress should be virtual
WM.Business.Classes.Contacts: method get_Lastname should be virtual
WM.Business.Classes.Contacts: method get_FirstName should be virtual
WM.Business.Classes.Contacts: method set_FirstName should be virtual
WM.Business.Classes.Contacts: method get_EmailAddress should be virtual
WM.Business.Classes.Contacts: method set_Lastname should be virtual
WM.Business.Classes.Contacts: method get_ContactID should be virtual"

Any thoughts? (it all seems pretty bog standard class and map to me? but then i admit i am not grasping this as quickly as i have other things

Map
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="WM.Business.Classes.Contacts, Business" table="Contacts" >
    <id name="ContactID" column="ContactID" type="Int32" unsaved-value="0">
      <generator class="identity" />
    </id>
    <property name="FirstName" column="FirstName" type="String" length="50" />
    <property name="Lastname" column="Lastname" type="String" length="50" />
    <property name="EmailAddress" column="EmailAddress" type="String" length="100" />
  </class>

</hibernate-mapping>

class
Code:
Public Class Contacts

        Protected mContactID As Integer
        Protected mFirstName As String
        Protected mLastname As String
        Protected mEmailAddress As String

        Public Sub New()

        End Sub

        Public Property ContactID() As Integer
            Get
                Return mContactID
            End Get
            Set(ByVal value As Integer)
                mContactID = value
            End Set
        End Property

        Public Property FirstName() As String
            Get
                Return mFirstName
            End Get
            Set(ByVal value As String)
                mFirstName = value
            End Set
        End Property

        Public Property Lastname() As String
            Get
                Return mLastname
            End Get
            Set(ByVal value As String)
                mLastname = value
            End Set
        End Property

        Public Property EmailAddress() As String
            Get
                Return mEmailAddress
            End Get
            Set(ByVal value As String)
                mEmailAddress = value
            End Set
        End Property

    End Class


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 07, 2007 2:32 pm 
Senior
Senior

Joined: Thu Feb 09, 2006 1:30 pm
Posts: 172
oblivionsy wrote:
Thanks, that did the trick (for that one!)

Then got some other errors which are in mapping files that im not using yet so have removed them for now, but am getting a few errors like this one

"The following types may not be used as proxies:
WM.Business.Classes.Contacts: method set_ContactID should be virtual
WM.Business.Classes.Contacts: method set_EmailAddress should be virtual
WM.Business.Classes.Contacts: method get_Lastname should be virtual
WM.Business.Classes.Contacts: method get_FirstName should be virtual
WM.Business.Classes.Contacts: method set_FirstName should be virtual
WM.Business.Classes.Contacts: method get_EmailAddress should be virtual
WM.Business.Classes.Contacts: method set_Lastname should be virtual
WM.Business.Classes.Contacts: method get_ContactID should be virtual"

Any thoughts? (it all seems pretty bog standard class and map to me? but then i admit i am not grasping this as quickly as i have other things

Map
Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="WM.Business.Classes.Contacts, Business" table="Contacts" >
    <id name="ContactID" column="ContactID" type="Int32" unsaved-value="0">
      <generator class="identity" />
    </id>
    <property name="FirstName" column="FirstName" type="String" length="50" />
    <property name="Lastname" column="Lastname" type="String" length="50" />
    <property name="EmailAddress" column="EmailAddress" type="String" length="100" />
  </class>

</hibernate-mapping>

class
Code:
Public Class Contacts

        Protected mContactID As Integer
        Protected mFirstName As String
        Protected mLastname As String
        Protected mEmailAddress As String

        Public Sub New()

        End Sub

        Public Property ContactID() As Integer
            Get
                Return mContactID
            End Get
            Set(ByVal value As Integer)
                mContactID = value
            End Set
        End Property

        Public Property FirstName() As String
            Get
                Return mFirstName
            End Get
            Set(ByVal value As String)
                mFirstName = value
            End Set
        End Property

        Public Property Lastname() As String
            Get
                Return mLastname
            End Get
            Set(ByVal value As String)
                mLastname = value
            End Set
        End Property

        Public Property EmailAddress() As String
            Get
                Return mEmailAddress
            End Get
            Set(ByVal value As String)
                mEmailAddress = value
            End Set
        End Property

    End Class


Either mark the class as lazy="false" or make the properties virtual. This is covered in many forum posts and the migration guide sergey mentioned.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 07, 2007 2:51 pm 
Beginner
Beginner

Joined: Fri Jun 01, 2007 4:55 pm
Posts: 24
What is considered better? Make them overridable or use the lazy=false? I guess lazy loading would be more efficient of there was a lot of items? (where only a few were used?)

Cheers


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