Hello,

We have built our production application using EJB 3.0 on JBoss Application 
server 4.0.3 SP1. Here is the description of the problem we are encountering:

The problem is really that JBoss can not load EJB 3.0 entity beans which map to 
more than one table in the database.

Here is the real life scenario that describes the problem.
 
?       The application schema contains an object called Application and it 
maps to it's own table in the database:
 
           create Table Application 
           {
               int          applicationId; (Primary key)
               varchar   name;
               varchar   description;         
           }
 
?       2. Then we have another security object called VirtualRight and it's 
table structure is:
 
          create Table VirtualRight 
           {
               int          virtualRightId; (Primary key)
               varchar   name;
               varchar   description;
               int          applicationId;  (Foreign key)        
           }
 
   There is one-to-many association between the application and virtual right 
objects.
 
    With EJB 3.0 the relationship between these 2 objects are defined in the 
following way:
 
    
   Application.java
  
   @Entity()
   public class Application
   {
 private int applicationId;
 private String name;
 private String description;
 private VirtualRight[] virtualRights;

@Id (generate = GeneratorType.AUTO)
             @Column (name = "applicationId")
        public int getApplicationId() {
                return applicationId;
         }

              @Column (name = "name")
        public String getName() {
                return name;
        }


             @Column (name = "description")
        public String getDescription() {
                return description;
        }

@OneToMany (cascade = CascadeType.ALL, fetch = FetchType.LAZY, 
                         mappedBy = "application")
        @IndexColumn(name = "appl_vright_index")
        public VirtualRight[] getVirtualRights() {
                return virtualRights;
        }
   }

   VirtualRight.java
   @Entity()
   public class VirtualRight
   {
 private int virtualRightId;
 private String name;
 private String description;
 private Application application;

 @Id (generate = GeneratorType.AUTO)
 @Column (name = "virtualRightId")
              public int getVirtualRightId() {
       return virtualRightId;
 }

 @Column (name = "name")
 public String getName() {
       return name;
 }

 @Column (name = "description")
  public String getDescription() {
       return description;
  }

 @ManyToOne
 @JoinColumn (name = "applicationId")
              public Application getApplication() {
        return application;
 }

 }

As can be seen from code, the Application object since has one-to-many 
relationship with VirtualRight, has to declare the member ?virtualRights? as an 
array or collection as per the EJB 3.0 specifications.

Also since the VirtualRight object has many-to-one relationship with 
Application, it has to declare member ?application?.
EJB 3.0 defines an interface called EntityManager as part of the Persistence 
API, that should be used from a session bean to load and store the 3.0 entity 
beans from the persistence store.
So here Is the sample code that loads an Application object based on name:

@PersistenceContext (type=PersistenceContextType.TRANSACTION)
private EntityManager manager;

public Application findApplicationByName(String appName) 
{
Query query = manager.createQuery("from Application a where a.name = :name");
Application appl = (Application)query.setParameter("name", 
appName).getSingleResult();
Return (appl);
}

The method ?findApplicationByName? uses the createQuery method defined by the 
EntityManager interface to fetch an Application object from the database. As 
can be seen from the code above the query is supposed to load the 
?virtualRights? member of the Application object if found and this is where the 
problem exists in the JBoss application server.

The query.getSingleResult() call fails with the exception message:

org.hibernate.HibernateException: null index column for collection: 
com.eds.autoeng.vcc.security.ejb.Application.virtualRights

In reality the Application object can exist without any corresponding 
VirtualRight objects and consequently the ?virtualRights? member would be null. 

Ironically the query fails as soon as you insert one VirtualRight in the 
database for an Application object. So to be more precise:

?       The Application object is loaded successfully when it has no associated 
VirtualRights populated.

?       The  query to load the Application object fails with the above 
mentioned exception soon after a VirtualRight is inserted in the database 
associated with the Application.

This behavior is really weird and points to some bug in the EJB 3.0 
implementation of JBoss application server, unless there is something wrong in 
the way the relations have been defined.

We have tested this application on the latest EJB 3.0 RC4 and it fails with the 
same reason.


An obvious workaround to this problem in the query implementation is to use 
named queries or native queries to load the Entity bean instances. Here is the 
code that loads the Application object using the NamedQuery feature from the 
EJB query language.

@Entity()
@NamedQuery (
   name="findApplicationWithName", 
   queryString="SELECT applicationId, description FROM Application a where 
a.name = :name"
)
public class Application implements java.io.Serializable
{

    ?.. Application class details 
}

Here is the Session bean that uses the NamedQuery to load the Application 
object.

public @Stateless class ApplicationsBean implements Applications 
{
       @PersistenceContext (type=PersistenceContextType.TRANSACTION)
       private EntityManager manager;
       public Application queryApplicationByName(String appName) 
       {
Object appIdAndDescr[] = 
(Object[])manager.createNamedQuery("findApplicationWithName")
                .setParameter("name", appName).getSingleResult();
                
        Application appl = null;
                
        if (appIdAndDescr != null)
        {       
                appl = new Application();
                appl.setName(appName);
                appl.setApplicationId(((Integer)appIdAndDescr[0]).intValue());
                appl.setDescription((String)appIdAndDescr[1]);
        }    
        return appl;
        }
}

Please note that the  above query does not load the Virtual rights associated 
with the Application object and so that brings us to the next hurdle - When you 
try to persist the 'Application' fetched after adding one or more 
VirtualRights, the merge operation fails.

We are running against time to solve this problem as the release date has 
already slipped.

Any help on resolving this issue will be greately appreciated.

Thanks,
Milind

View the original post : 
http://www.jboss.com/index.html?module=bb&op=viewtopic&p=3921064#3921064

Reply to the post : 
http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=3921064


-------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc. Do you grep through log files
for problems?  Stop!  Download the new AJAX search engine that makes
searching your log files as easy as surfing the  web.  DOWNLOAD SPLUNK!
http://sel.as-us.falkag.net/sel?cmd=lnk&kid=103432&bid=230486&dat=121642
_______________________________________________
JBoss-user mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/jboss-user

Reply via email to