-->
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.  [ 20 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: explicit interface implemenation
PostPosted: Fri Jun 29, 2007 5:04 pm 
Newbie

Joined: Fri Jun 29, 2007 4:53 pm
Posts: 13
Hi all,

Here is my scenario, I have an interface called IPersistenceMetaData. It has four properties (CreatedBy, CreatedOn, ModifiedBy, ModifiedOn). I explicitly implelment the interface on an abstract class called EntityBase. I also have a Guid Id property on entity base. All of my entity classes inherit from EntityBase. For testing purposes I created a class called TestEntity which inherits from EntityBase. TestEntity has one property called Name. I created my hbm.xml file for TestEntity. I had nhibernate generate the tables, which it did successfully. The table TestEntity has the following columns now Id, Name, CreatedBy, CreatedOn, ModifiedBy, and ModifiedOn. In a test program I create a new instance of TestEntity and set the Name property. Next I cast TestEntity to the IPersistenceMetaData interface and set the CreatedBy and CreatedOn properties. I save the entity using the current session and then flush. I check the database and all the columns are populated properly. Next I cache the id in a variable and Evict the instance of TestEntity. Finally I use the session to do a Load<TestEntity>. It loads fine except that the CreatedBy and CreatedOn properties are not set to what was saved in the db. Is there a way to accomplish what I am trying without having to resort to implicitly implementing the IPersistenceMetaData interface?

Thanks,

Justin


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 02, 2007 11:30 am 
Newbie

Joined: Fri Jun 29, 2007 4:53 pm
Posts: 13
Hi All,

So no one has any ideas on this? I am assuming what I am trying to accomplish is not possible without customization.

Thanks,

Justin


Top
 Profile  
 
 Post subject: Re: explicit interface implemenation
PostPosted: Mon Jul 02, 2007 12:52 pm 
Senior
Senior

Joined: Thu Feb 09, 2006 1:30 pm
Posts: 172
jechternach wrote:
It loads fine except that the CreatedBy and CreatedOn properties are not set to what was saved in the db. Is there a way to accomplish what I am trying without having to resort to implicitly implementing the IPersistenceMetaData interface?


Something else must be going on. NHibernate will work fine with explicit interface implementations. I have done it for some of my classes. I assume you are using 1.2.0?

What if you open a new session, are you seeing the same result?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 02, 2007 1:37 pm 
Newbie

Joined: Fri Jun 29, 2007 4:53 pm
Posts: 13
I am using version 1.2.0.

Here is the hbm.xml file ...

Code:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
   namespace="Core" assembly="Core" >
   <class name="TestEntity" table="TestEntity">
      <id name="Id">
         <column name="TestEntityId" not-null="true" />
         <generator class="guid.comb" />
      </id>

      <property name="Name">
         <column name="Name" not-null="true" />
      </property>

      <property name="CreatedBy">
         <column name="CreatedBy" not-null="true" />
      </property>

      <property name="CreatedOn">
         <column name="CreatedOn" not-null="true" />
      </property>

      <property name="ModifiedBy">
         <column name="ModifiedBy" not-null="false" />
      </property>

      <property name="ModifiedOn">
         <column name="ModifiedOn" not-null="false" />
      </property>
   </class>
</hibernate-mapping>


Here is the interface ...

Code:
namespace Core
{
    public interface IPersistenceMetaData
    {
        string CreatedBy { get; set; }

        DateTime CreatedOn { get; set; }

        string ModifiedBy { get; set; }
       
        DateTime? ModifiedOn { get; set; }
    }
}


Here is the abstract base class ...

Code:
namespace Core
{
    public abstract class EntityBase : IPersistenceMetaData
    {
        private Guid id;

        private string createdBy;
        private DateTime createdOn;
        private string modifiedBy;
        private DateTime? modifiedOn;

        public virtual Guid Id
        {
            get { return this.id; }
            set { this.id = value; }
        }

        #region IPersistenceMetaData Members

        string IPersistenceMetaData.CreatedBy
        {
            get { return this.createdBy; }
            set { this.createdBy = value; }
        }

        DateTime IPersistenceMetaData.CreatedOn
        {
            get { return this.createdOn; }
            set { this.createdOn = value; }
        }

        string IPersistenceMetaData.ModifiedBy
        {
            get { return this.modifiedBy; }
            set { this.modifiedBy = value; }
        }

        DateTime? IPersistenceMetaData.ModifiedOn
        {
            get { return this.modifiedOn; }
            set { this.modifiedOn = value; }
        }

        #endregion
    }
}


Here is the test entity class ...

Code:
namespace Core
{
    public class TestEntity : EntityBase
    {
       
        private string name;

        public TestEntity()
        {
        }

        public TestEntity(string name)
        {
            this.name = name;
        }

        public virtual string Name
        {
            get { return this.name; }
            set { this.name = value; }
        }

    }
}


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 02, 2007 4:55 pm 
Newbie

Joined: Fri Jun 29, 2007 4:53 pm
Posts: 13
I just noticed I had posted the code for EntityBase that implements the insterface implicitly. I edited now to implement the interface explicitly.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 03, 2007 3:59 am 
Beginner
Beginner

Joined: Tue Mar 27, 2007 4:54 am
Posts: 47
I guess you are using a proxy? In that case the props and methods manipulating the entity data needs to be virtual, letting the proxy subclassing your methods correctly.

Explicit interface implementation doesn't support to be virtual. You need to do some workaround like (only showing one property here) this...

string IPersistenceMetaData.CreatedBy
{
get { return CreatedBy; }
set { CreatedBy=value; }
}

protected virtual string CreatedBy
{
get { return createdBy; }
set { createdBy = value; }
}

...which I guess is sort of best practise when using explicit interfaces anyhow (expose the interface's functionallity to the derived classes).

Regards
Roger


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 03, 2007 11:58 am 
Newbie

Joined: Fri Jun 29, 2007 4:53 pm
Posts: 13
I believe that when you explicitly implement an interface it's properties and methods are automatically virtual on the implementing class. Also, NHibernate has no problem saving the data to the database, it just doesn't set the properties from the interface when reconstituting the object from the database.

I want the explicit implementation so that the persistence metadata properties aren't seen in intellisense when working with entity classes. I have a special class that takes an entity and sets those properties automatically, before persisting the entity to the database.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 03, 2007 2:57 pm 
Senior
Senior

Joined: Thu Feb 09, 2006 1:30 pm
Posts: 172
But how are you positive those values are being updated? You are checking the database? Are you sure they aren't again updated at a later point in time?

Did you try using one session, and then try using multiple sessions so you see what is really taking place. Are you using a second level cache where these values possibly aren't being stored in the cache, and then whatever you loaded the first time is coming back instead?

Try removing the cache to see what happens.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Jul 03, 2007 3:28 pm 
Newbie

Joined: Fri Jun 29, 2007 4:53 pm
Posts: 13
Here is the test code below. I check the database after the flush and the CreatedBy and CreatedOn columns have the correct information.

After I do the evict and load the data from the table, CreatedOn and CreatedBy are not loaded. The name and id are though.

Code:
DBGenerator.GenerateDBSchema();

            TestEntity test = new TestEntity("justin");

            IPersistenceMetaData pmd = (IPersistenceMetaData)test;

            pmd.CreatedBy = "jechternach";
            pmd.CreatedOn = DateTime.Now;


            NHibernateSessionModule.CurrentSession.Save(test);

            NHibernateSessionModule.CurrentSession.Flush();

            Guid testId = test.Id;

            NHibernateSessionModule.CurrentSession.Evict(test);

            TestEntity test2 = NHibernateSessionModule.CurrentSession.Load<TestEntity>(testId);

            IPersistenceMetaData pmd2 = (IPersistenceMetaData)test2;


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jul 04, 2007 2:16 am 
Newbie

Joined: Thu May 03, 2007 7:24 am
Posts: 6
If this helps ...

I tried using the code you posted. I set it up under NUnit & ran the test. It retrieved CreatedBy & CreatedDate successfully.

The only change I made was to replace the helper functions in your test with native NHibernate calls. Can't imagine that would have made a difference. I was using SQL 2005.

Have you tried turning on logging to locate the problem?

Cheers,
-Naraen

_________________
Naraendirakumar R.R.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 05, 2007 10:41 am 
Newbie

Joined: Fri Jun 29, 2007 4:53 pm
Posts: 13
Hmmm... You implemented the interface explicitly on EntityBase? Did you have to add anything to the hbm xml file about the IPersistenceMetaData interface?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 05, 2007 3:18 pm 
Newbie

Joined: Fri Jun 29, 2007 4:53 pm
Posts: 13
Ok, I got it to work, but I had to set lazy="false" in hbm.xml. So, I guess it has something to do with proxy losing the values. I looked at the logs and whether I have lazy set to false or true when it loads the TestEntity it does retrieve the correct values for CreatedOn and CreatedBy. The proxy just doesn't get them for some reason. Is it possible to create a custom proxy to handle this? What are the ramifications of having lazy set to false?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 05, 2007 3:55 pm 
Beginner
Beginner

Joined: Tue Mar 27, 2007 4:54 am
Posts: 47
<<I believe that when you explicitly implement an interface it's properties and methods are automatically virtual on the implementing class. >>

No. Explicit interface implementations are always private and therefore non virtual.
I suggest you reread my former post and give it a try.

Good luck
Roger


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 05, 2007 4:10 pm 
Newbie

Joined: Fri Jun 29, 2007 4:53 pm
Posts: 13
You are incorrect. When you explicitly implement an interface you do not specify public and virtual because they are automatically public and virtual. If they were private then when I cast to that interface I wouldn't be able to access the properties, but I can. Since it is an explicit implementation I have to cast to the IPersistenceMetaData interface if I want access to its properties.

Anyway I have gotten it to work two different ways. The original way I posted above with lazy set to false. I also got it to work by inheriting from ITestEntity, which inherits from IEntity which inherits from IPersistenceMetaData. I am no longer using EntityBase. I set the proxy attribute for the TestEntity class to ITestEntity. This way works and allows lazy initialization. The one caveat is the generic version of Session.Load<TestEntity>(testEntityId) doesn't work (throws a cast exception). I have to use Session.Load(typeof(TestEntity), testEntityId);

I believe the way you suggested is basically to do an implicit implementation of the interface which is what I am trying to avoid.

Thanks for the input.


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jul 05, 2007 4:29 pm 
Newbie

Joined: Fri Jun 29, 2007 4:53 pm
Posts: 13
Actually we are both correct ...

Quote:
Explicit interface member implementations have different accessibility characteristics than other members. 2 Because explicit interface member implementations are never accessible through their fully qualified name in a method invocation or a property access, they are in a sense private. 3 However, since they can be accessed through an interface instance, they are in a sense also public.


http://www.jaggersoft.com/csharp_standard/20.4.1.htm paragraph 4

I will try your method as well. I will let you know the results.


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