EJ3 Problem. LEFT JOIN doesn磘 work with ManyToMany relations

I have two entities, Project and Tool that they have a many to many relation. I execute this sql query and I don`t get any result:

List<Project> resul = em.createQuery("SELECT p FROM Project p LEFT JOIN p.tools t").getResultList();

In the database there is one row in Project table that doesn't point to any Tool. I don't understand why doesnt' return any row.

@Entity

public class Project implements Serializable

{

@Id

@GeneratedValue(strategy = GenerationType.IDENTITY)

private Long idProject;

private String name;

private String description;

@ManyToMany

@JoinTable(name="Tool_Project",

joinColumns=@JoinColumn(name="IdProject"),

inverseJoinColumns=@JoinColumn(name="idTool"))

private Collection<Tool> tools;

....

}

@Entity

public class Tool implements Serializable

{

@Id

@GeneratedValue(strategy = GenerationType.IDENTITY)

private Long idTool;

private String name;

@ManyToMany(mappedBy="tools")

private Collection<Project> projects;

....

}

Thank you in advance.

Hayken

[1180 byte] By [haykena] at [2007-11-27 4:31:52]
# 1

The sql query generated by toplink is erroneous.

In this url you can see the code bug. Besides It is marked with bug id (4240751).

http://fisheye5.cenqua.com/browse/glassfish/entity-persistence/src/java/oracle/toplink/essentials/internal/expressions/SQLSelectStatement.java?r=1.17

Oracle says that have fixed this bug in the comercial version of toplink but this mistake hasn磘 been corrected in toplink essentials

http://www.oracle.com/technology/products/ias/toplink/technical/relnotes/tl_relnotes.htm

I have downloaded the source code of toplink essentials and I fixed this bug. I have compiled it and I have tested. Now it works. I hope that fix soon this bug for future versions.

Now I am going to show this fixed bug. I have commented the parts of original code that doesn磘 work and marked that I have modified.

//Bug#4240751 Treat ManyToManyMapping separately for out join

} else if (outerExpression.getMapping().isManyToManyMapping()) {

// Must outerjoin each of the targets tables.

// The first table is joined with the mapping join criteria,

// the rest of the tables are joined with the additional join criteria.

// For example: EMPLOYEE t1 LEFT OUTER JOIN (PROJ_EMP t3 LEFT OUTER JOIN PROJECT t0 ON (t0.PROJ_ID = t3.PROJ_ID)) ON (t3.EMP_ID = t1.EMP_ID)

DatabaseTable relationTable = ((ManyToManyMapping)outerExpression.getMapping()).getRelationTable();

DatabaseTable relationAlias = ((Expression)getOuterJoinedMappingCriteria().elementAt(index)).aliasForTable(relationTable);

//writer.write(" LEFT OUTER JOIN (");

writer.write(" LEFT OUTER JOIN "); // hayken

writer.write(relationTable.getQualifiedName());

writer.write(" ");

outerJoinedAliases.addElement(relationAlias);

writer.write(relationAlias.getQualifiedName());

Vector tablesInOrder = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(3);

// glassfish issue 2440: store aliases instead of tables

// in the tablesInOrder. This allows to distinguish source

// and target table in case of an self referencing relationship.

tablesInOrder.add(sourceAlias);

tablesInOrder.add(relationAlias);

tablesInOrder.add(targetAlias);

TreeMap indexToExpressionMap = new TreeMap();

mapTableIndexToExpression((Expression)getOuterJoinedMappingCriteria().elementAt(index), indexToExpressionMap, tablesInOrder);

Expression sourceToRelationJoin = (Expression)indexToExpressionMap.get(new Integer(1));

Expression relationToTargetJoin = (Expression)indexToExpressionMap.get(new Integer(2));

// hayken {

writer.write(" ON ");

if (session.getPlatform() instanceof DB2MainframePlatform) {

((RelationExpression)sourceToRelationJoin).printSQLNoParens(printer);

} else {

sourceToRelationJoin.printSQL(printer);

}

// hayken }

//writer.write(" JOIN ");

writer.write(" LEFT OUTER JOIN "); // hayken

writer.write(targetTable.getQualifiedName());

writer.write(" ");

outerJoinedAliases.addElement(targetAlias);

writer.write(targetAlias.getQualifiedName());

writer.write(" ON ");

if (session.getPlatform() instanceof DB2MainframePlatform) {

((RelationExpression)relationToTargetJoin).printSQLNoParens(printer);

} else {

relationToTargetJoin.printSQL(printer);

}

Map tablesJoinExpression = (Map)getOuterJoinedAdditionalJoinCriteria().elementAt(index);

if(tablesJoinExpression != null && !tablesJoinExpression.isEmpty()) {

printAdditionalJoins(printer, outerJoinedAliases, outerExpression.getMapping().getReferenceDescriptor(), tablesJoinExpression);

}

/*writer.write(") ON ");

if (session.getPlatform() instanceof DB2MainframePlatform) {

((RelationExpression)sourceToRelationJoin).printSQLNoParens(printer);

} else {

sourceToRelationJoin.printSQL(printer);

}*/

}

hayken

haykena at 2007-7-12 9:41:22 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...