You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@olingo.apache.org by ch...@apache.org on 2015/01/18 09:48:57 UTC

olingo-odata2 git commit: [OLINGO-411] Fix for handling JPA self joins

Repository: olingo-odata2
Updated Branches:
  refs/heads/master c9db4f530 -> f37322567


[OLINGO-411] Fix for handling JPA self joins

Project: http://git-wip-us.apache.org/repos/asf/olingo-odata2/repo
Commit: http://git-wip-us.apache.org/repos/asf/olingo-odata2/commit/f3732256
Tree: http://git-wip-us.apache.org/repos/asf/olingo-odata2/tree/f3732256
Diff: http://git-wip-us.apache.org/repos/asf/olingo-odata2/diff/f3732256

Branch: refs/heads/master
Commit: f37322567aa2f83c7ee6b280fb7480e17e585c6b
Parents: c9db4f5
Author: Chandan V A <ch...@sap.com>
Authored: Sun Jan 18 14:18:10 2015 +0530
Committer: Chandan V A <ch...@sap.com>
Committed: Sun Jan 18 14:18:10 2015 +0530

----------------------------------------------------------------------
 .../core/access/model/JPAEdmNameBuilder.java    |  87 ++++---
 .../processor/core/model/JPAEdmAssociation.java |   7 +-
 .../processor/core/model/JPAEdmProperty.java    |  20 +-
 .../model/JPAEdmReferentialConstraintRole.java  |   8 +-
 .../core/model/JPAEdmPropertyTest.java          | 226 +++++++++++++++----
 5 files changed, 263 insertions(+), 85 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f3732256/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/model/JPAEdmNameBuilder.java
----------------------------------------------------------------------
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/model/JPAEdmNameBuilder.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/model/JPAEdmNameBuilder.java
index 939ca88..352016e 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/model/JPAEdmNameBuilder.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/access/model/JPAEdmNameBuilder.java
@@ -26,6 +26,7 @@ import javax.persistence.metamodel.Attribute;
 import javax.persistence.metamodel.ManagedType;
 import javax.persistence.metamodel.PluralAttribute;
 
+import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
 import org.apache.olingo.odata2.api.edm.FullQualifiedName;
 import org.apache.olingo.odata2.api.edm.provider.Association;
 import org.apache.olingo.odata2.api.edm.provider.AssociationSet;
@@ -142,12 +143,15 @@ public class JPAEdmNameBuilder {
                 jpaAttributeName);
       }
     }
+    if (isForeignKey == true) {
+      joinColumnNames = view.getJPAJoinColumns().get(view.getJPAJoinColumns().size() - 1);
+    }
+
     if (skipDefaultNaming == false && propertyName == null) {
       propertyName = Character.toUpperCase(jpaAttributeName.charAt(0)) + jpaAttributeName.substring(1);
     } else if (propertyName == null) {
       propertyName = jpaAttributeName;
-      if (isForeignKey == true) {
-        joinColumnNames = view.getJPAJoinColumns().get(view.getJPAJoinColumns().size() - 1);
+      if (isForeignKey) {
         propertyName = mappingModelAccess.mapJPAAttribute(view.getJPAEdmEntityTypeView().getJPAEntityType().getName(),
             joinColumnNames[0]);
         if (propertyName == null) {
@@ -379,19 +383,6 @@ public class JPAEdmNameBuilder {
 
   }
 
-  private static String buildNamespace(final JPAEdmBaseView view) {
-    JPAEdmMappingModelAccess mappingModelAccess = view.getJPAEdmMappingModelAccess();
-    String namespace = null;
-    if (mappingModelAccess != null && mappingModelAccess.isMappingModelExists()) {
-      namespace = mappingModelAccess.mapJPAPersistenceUnit(view.getpUnitName());
-    }
-    if (namespace == null) {
-      namespace = view.getpUnitName();
-    }
-
-    return namespace;
-  }
-
   /*
    * ************************************************************************
    * EDM Association Name - RULES
@@ -408,16 +399,23 @@ public class JPAEdmNameBuilder {
     String end1Name = association.getEnd1().getType().getName();
     String end2Name = association.getEnd2().getType().getName();
 
-    if (end1Name.compareToIgnoreCase(end2Name) > 0) {
-      associationName = end2Name + UNDERSCORE + end1Name;
-    } else {
+    if (end1Name.equals(end2Name)) {
       associationName = end1Name + UNDERSCORE + end2Name;
+      associationName =
+          associationName + UNDERSCORE + multiplicityToString(association.getEnd1().getMultiplicity()) + UNDERSCORE
+              + multiplicityToString(association.getEnd2().getMultiplicity()) + Integer.toString(count);
+    } else {
+      if (end1Name.compareToIgnoreCase(end2Name) > 0) {
+        associationName = end2Name + UNDERSCORE + end1Name;
+      } else {
+        associationName = end1Name + UNDERSCORE + end2Name;
+      }
+      if (count > 1) {
+        associationName = associationName + Integer.toString(count - 1);
+      }
     }
-    if (count > 1) {
-      associationName = associationName + Integer.toString(count - 1);
-    }
-    association.setName(associationName);
 
+    association.setName(associationName);
   }
 
   /*
@@ -506,11 +504,21 @@ public class JPAEdmNameBuilder {
     // Condition for self join
     if (associationEndTypeOne.getName().equals(associationEndTypeTwo.getName())) {
       if (jpaAttribute.isCollection()) {
-        navProp.setFromRole(association.getEnd2().getRole());
-        navProp.setToRole(association.getEnd1().getRole());
+        if (association.getEnd2().getMultiplicity().equals(EdmMultiplicity.MANY)) {
+          navProp.setToRole(association.getEnd2().getRole());
+          navProp.setFromRole(association.getEnd1().getRole());
+        } else {
+          navProp.setToRole(association.getEnd1().getRole());
+          navProp.setFromRole(association.getEnd2().getRole());
+        }
       } else {
-        navProp.setToRole(association.getEnd2().getRole());
-        navProp.setFromRole(association.getEnd1().getRole());        
+        if (association.getEnd2().getMultiplicity().equals(EdmMultiplicity.ONE)) {
+          navProp.setToRole(association.getEnd2().getRole());
+          navProp.setFromRole(association.getEnd1().getRole());
+        } else {
+          navProp.setToRole(association.getEnd1().getRole());
+          navProp.setFromRole(association.getEnd2().getRole());
+        }
       }
     } else if (toName.equals(associationEndTypeOne.getName())) {
       navProp.setFromRole(association.getEnd2().getRole());
@@ -522,4 +530,31 @@ public class JPAEdmNameBuilder {
     }
   }
 
+  private static String multiplicityToString(EdmMultiplicity multiplicity) {
+    switch (multiplicity) {
+    case MANY:
+      return "Many";
+    case ONE:
+      return "One";
+    case ZERO_TO_ONE:
+      return "ZeroToOne";
+    default:
+      break;
+    }
+    return "";
+  }
+
+  private static String buildNamespace(final JPAEdmBaseView view) {
+    JPAEdmMappingModelAccess mappingModelAccess = view.getJPAEdmMappingModelAccess();
+    String namespace = null;
+    if (mappingModelAccess != null && mappingModelAccess.isMappingModelExists()) {
+      namespace = mappingModelAccess.mapJPAPersistenceUnit(view.getpUnitName());
+    }
+    if (namespace == null) {
+      namespace = view.getpUnitName();
+    }
+
+    return namespace;
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f3732256/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/model/JPAEdmAssociation.java
----------------------------------------------------------------------
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/model/JPAEdmAssociation.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/model/JPAEdmAssociation.java
index 9f35c3a..889047c 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/model/JPAEdmAssociation.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/model/JPAEdmAssociation.java
@@ -217,8 +217,6 @@ public class JPAEdmAssociation extends JPAEdmBaseViewImpl implements JPAEdmAssoc
   @Override
   public int getNumberOfAssociationsWithSimilarEndPoints(final JPAEdmAssociationEndView view) {
     int count = 0;
-    AssociationEnd currentAssociationEnd1 = view.getEdmAssociationEnd1();
-    AssociationEnd currentAssociationEnd2 = view.getEdmAssociationEnd2();
     AssociationEnd end1 = null;
     AssociationEnd end2 = null;
     for (String key : associationMap.keySet()) {
@@ -226,10 +224,7 @@ public class JPAEdmAssociation extends JPAEdmBaseViewImpl implements JPAEdmAssoc
       if (association != null) {
         end1 = association.getEnd1();
         end2 = association.getEnd2();
-        if ((end1.getType().equals(currentAssociationEnd1.getType()) && end2.getType().equals(
-            currentAssociationEnd2.getType()))
-            || (end1.getType().equals(currentAssociationEnd2.getType()) && end2.getType().equals(
-                currentAssociationEnd1.getType()))) {
+        if (view.compare(end1, end2)) {
           count++;
         }
       }

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f3732256/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/model/JPAEdmProperty.java
----------------------------------------------------------------------
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/model/JPAEdmProperty.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/model/JPAEdmProperty.java
index 369f6b9..fbb8f96 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/model/JPAEdmProperty.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/model/JPAEdmProperty.java
@@ -276,7 +276,10 @@ public class JPAEdmProperty extends JPAEdmBaseViewImpl implements
         case ONE_TO_ONE:
         case MANY_TO_ONE:
 
-          addForeignKey(currentAttribute);
+          if (attributeType.equals(PersistentAttributeType.MANY_TO_ONE)
+              || attributeType.equals(PersistentAttributeType.ONE_TO_ONE)) {
+            addForeignKey(currentAttribute);
+          }
 
           JPAEdmAssociationEndView associationEndView = new JPAEdmAssociationEnd(entityTypeView, JPAEdmProperty.this);
           associationEndView.getBuilder().build();
@@ -289,14 +292,17 @@ public class JPAEdmProperty extends JPAEdmBaseViewImpl implements
             associationView.addJPAEdmAssociationView(associationViewLocal, associationEndView);
           }
 
-          JPAEdmReferentialConstraintView refConstraintView = new JPAEdmReferentialConstraint(
-              associationView, entityTypeView, JPAEdmProperty.this);
-          refConstraintView.getBuilder().build();
+          if (attributeType.equals(PersistentAttributeType.MANY_TO_ONE)
+              || attributeType.equals(PersistentAttributeType.ONE_TO_ONE)) {
 
-          if (refConstraintView.isExists()) {
-            associationView.addJPAEdmRefConstraintView(refConstraintView);
-          }
+            JPAEdmReferentialConstraintView refConstraintView = new JPAEdmReferentialConstraint(
+                associationView, entityTypeView, JPAEdmProperty.this);
+            refConstraintView.getBuilder().build();
 
+            if (refConstraintView.isExists()) {
+              associationView.addJPAEdmRefConstraintView(refConstraintView);
+            }
+          }
           if (navigationPropertyView == null) {
             navigationPropertyView = new JPAEdmNavigationProperty(schemaView);
           }

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f3732256/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/model/JPAEdmReferentialConstraintRole.java
----------------------------------------------------------------------
diff --git a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/model/JPAEdmReferentialConstraintRole.java b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/model/JPAEdmReferentialConstraintRole.java
index 2a5045a..9c3c89e 100644
--- a/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/model/JPAEdmReferentialConstraintRole.java
+++ b/odata2-jpa-processor/jpa-core/src/main/java/org/apache/olingo/odata2/jpa/processor/core/model/JPAEdmReferentialConstraintRole.java
@@ -141,6 +141,7 @@ public class JPAEdmReferentialConstraintRole extends JPAEdmBaseViewImpl implemen
 
     private void buildRole() throws SecurityException, NoSuchFieldException {
 
+      int index = 0;
       if (currentRole == null) {
         currentRole = new ReferentialConstraintRole();
         String jpaAttributeType = null;
@@ -157,6 +158,7 @@ public class JPAEdmReferentialConstraintRole extends JPAEdmBaseViewImpl implemen
             jpaAttributeType = type.toString().substring(lastIndexOfDot + 1);
           }
           edmEntityType = entityTypeView.searchEdmEntityType(jpaAttributeType);
+          index = 1;
         } else if (roleType == RoleType.DEPENDENT) {
           edmEntityType =
               entityTypeView.searchEdmEntityType(jpaAttribute.getDeclaringType().getJavaType().getSimpleName());
@@ -167,10 +169,8 @@ public class JPAEdmReferentialConstraintRole extends JPAEdmBaseViewImpl implemen
           for (String[] columnName : jpaColumnNames) {
             for (Property property : edmEntityType.getProperties()) {
               jpaColumnName = ((JPAEdmMapping) property.getMapping()).getJPAColumnName();
-              if (columnName[0].equals(jpaColumnName) ||
-                  columnName[0].equals(property.getName()) ||
-                  columnName[1].equals(jpaColumnName) ||
-                  columnName[1].equals(property.getName())) {
+              if (columnName[index].equals(jpaColumnName) ||
+                  columnName[index].equals(property.getName())) {
                 PropertyRef propertyRef = new PropertyRef();
                 propertyRef.setName(property.getName());
                 propertyRefs.add(propertyRef);

http://git-wip-us.apache.org/repos/asf/olingo-odata2/blob/f3732256/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/model/JPAEdmPropertyTest.java
----------------------------------------------------------------------
diff --git a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/model/JPAEdmPropertyTest.java b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/model/JPAEdmPropertyTest.java
index c204d1f..f76a50f 100644
--- a/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/model/JPAEdmPropertyTest.java
+++ b/odata2-jpa-processor/jpa-core/src/test/java/org/apache/olingo/odata2/jpa/processor/core/model/JPAEdmPropertyTest.java
@@ -24,9 +24,13 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Member;
 import java.util.HashSet;
 import java.util.Set;
 
+import javax.persistence.Column;
+import javax.persistence.JoinColumn;
 import javax.persistence.metamodel.Attribute;
 import javax.persistence.metamodel.Attribute.PersistentAttributeType;
 import javax.persistence.metamodel.EmbeddableType;
@@ -34,9 +38,11 @@ import javax.persistence.metamodel.EntityType;
 import javax.persistence.metamodel.Metamodel;
 import javax.persistence.metamodel.Type;
 
+import org.apache.olingo.odata2.api.edm.EdmMultiplicity;
 import org.apache.olingo.odata2.api.edm.FullQualifiedName;
 import org.apache.olingo.odata2.api.edm.provider.Association;
 import org.apache.olingo.odata2.api.edm.provider.AssociationEnd;
+import org.apache.olingo.odata2.api.edm.provider.NavigationProperty;
 import org.apache.olingo.odata2.api.edm.provider.Schema;
 import org.apache.olingo.odata2.jpa.processor.api.access.JPAEdmBuilder;
 import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPAModelException;
@@ -51,15 +57,18 @@ import org.apache.olingo.odata2.jpa.processor.core.mock.model.JPAEdmMockData.Com
 import org.apache.olingo.odata2.jpa.processor.core.mock.model.JPAEdmMockData.SimpleType;
 import org.apache.olingo.odata2.jpa.processor.core.mock.model.JPAEmbeddableTypeMock;
 import org.apache.olingo.odata2.jpa.processor.core.mock.model.JPAEntityTypeMock;
+import org.apache.olingo.odata2.jpa.processor.core.mock.model.JPAJavaMemberMock;
 import org.apache.olingo.odata2.jpa.processor.core.mock.model.JPAMetaModelMock;
 import org.apache.olingo.odata2.jpa.processor.core.mock.model.JPAPluralAttributeMock;
 import org.apache.olingo.odata2.jpa.processor.core.mock.model.JPASingularAttributeMock;
+import org.easymock.EasyMock;
 import org.junit.Test;
 
 public class JPAEdmPropertyTest extends JPAEdmTestModelView {
 
   private JPAEdmPropertyTest objJPAEdmPropertyTest;
   private JPAEdmProperty objJPAEdmProperty;
+  private static java.lang.String testCase = "Default";
 
   private static PersistentAttributeType ATTRIBUTE_TYPE = PersistentAttributeType.BASIC;
 
@@ -157,8 +166,30 @@ public class JPAEdmPropertyTest extends JPAEdmTestModelView {
   @Test
   public void testBuildManyToOne() {
     ATTRIBUTE_TYPE = PersistentAttributeType.MANY_TO_ONE;
+    testCase = "Default";
     objJPAEdmPropertyTest = new JPAEdmPropertyTest();
     objJPAEdmProperty = new JPAEdmProperty(objJPAEdmPropertyTest);
+
+    try {
+      objJPAEdmProperty.getBuilder().build();
+    } catch (ODataJPAModelException e) {
+      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
+    } catch (ODataJPARuntimeException e) {
+      fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
+    }
+
+    NavigationProperty navigationProperty =
+        objJPAEdmProperty.getJPAEdmNavigationPropertyView().getEdmNavigationProperty();
+    assertNotNull(navigationProperty);
+  }
+
+  @Test
+  public void testBuildManyToOneNoJoinColumnNames() {
+    ATTRIBUTE_TYPE = PersistentAttributeType.MANY_TO_ONE;
+    testCase = "NoJoinColumnNames";
+    objJPAEdmPropertyTest = new JPAEdmPropertyTest();
+    objJPAEdmProperty = new JPAEdmProperty(objJPAEdmPropertyTest);
+
     try {
       objJPAEdmProperty.getBuilder().build();
     } catch (ODataJPAModelException e) {
@@ -167,7 +198,12 @@ public class JPAEdmPropertyTest extends JPAEdmTestModelView {
       fail(ODataJPATestConstants.EXCEPTION_MSG_PART_1 + e.getMessage() + ODataJPATestConstants.EXCEPTION_MSG_PART_2);
     }
 
-    assertNotNull(objJPAEdmProperty.getJPAEdmNavigationPropertyView().getEdmNavigationProperty());
+    NavigationProperty navigationProperty =
+        objJPAEdmProperty.getJPAEdmNavigationPropertyView().getEdmNavigationProperty();
+    assertNotNull(navigationProperty);
+    assertEquals("String", navigationProperty.getFromRole());
+    assertEquals("salesorderprocessing", navigationProperty.getToRole());
+    assertEquals("StringDetails", navigationProperty.getName());
   }
 
   @Override
@@ -227,9 +263,20 @@ public class JPAEdmPropertyTest extends JPAEdmTestModelView {
   @Override
   public Association getEdmAssociation() {
     Association association = new Association();
+    AssociationEnd end1 = new AssociationEnd();
+    end1.setType(new FullQualifiedName("salesorderprocessing", "SalesOrderHeader"));
+    end1.setMultiplicity(EdmMultiplicity.MANY);
+    end1.setRole("salesorderprocessing");
+
+    AssociationEnd end2 = new AssociationEnd();
+    end2.setType(new FullQualifiedName("String", "SalesOrderHeader"));
+    end2.setMultiplicity(EdmMultiplicity.ONE);
+    end2.setRole("String");
+
     association
-        .setEnd1(new AssociationEnd().setType(new FullQualifiedName("salesorderprocessing", "SalesOrderHeader")));
-    association.setEnd2(new AssociationEnd().setType(new FullQualifiedName("salesorderprocessing", "String")));
+        .setEnd1(end1);
+    association.setEnd2(end2);
+    association.setName("salesorderprocessing_String");
 
     return association;
   }
@@ -254,6 +301,58 @@ public class JPAEdmPropertyTest extends JPAEdmTestModelView {
     return this;
   }
 
+  @Override
+  public Attribute<?, ?> getJPAReferencedAttribute() {
+    JPAEdmAttribute<Object, String> refAttribute =
+        new JPAEdmAttribute<Object, String>(java.lang.String.class, "SOLITID");
+
+    return refAttribute;
+  }
+
+  @SuppressWarnings("hiding")
+  private static class JPAEdmAttribute<Object, String> extends JPASingularAttributeMock<Object, String> {
+
+    @Override
+    public PersistentAttributeType getPersistentAttributeType() {
+      if (attributeName.equals("SOLITID")) {
+        return PersistentAttributeType.BASIC;
+      }
+      return ATTRIBUTE_TYPE;
+    }
+
+    Class<String> clazz;
+    java.lang.String attributeName;
+
+    public JPAEdmAttribute(final Class<String> javaType, final java.lang.String name) {
+      this.clazz = javaType;
+      this.attributeName = name;
+
+    }
+
+    @Override
+    public Class<String> getJavaType() {
+      return clazz;
+    }
+
+    @Override
+    public java.lang.String getName() {
+      return this.attributeName;
+    }
+
+    @Override
+    public boolean isId() {
+      return true;
+    }
+
+    @Override
+    public Member getJavaMember() {
+      if (this.attributeName.equals("SOLITID")) {
+        return new JPAJavaMember();
+      }
+      return null;
+    }
+  }
+
   private class JPAEdmMetaModel extends JPAMetaModelMock {
     Set<EntityType<?>> entities;
     Set<EmbeddableType<?>> embeddableSet;
@@ -265,7 +364,7 @@ public class JPAEdmPropertyTest extends JPAEdmTestModelView {
 
     @Override
     public Set<EntityType<?>> getEntities() {
-      entities.add(new JPAEdmEntityType());
+      entities.add(new JPAEdmEntityType<String>());
       return entities;
     }
 
@@ -275,16 +374,39 @@ public class JPAEdmPropertyTest extends JPAEdmTestModelView {
       return embeddableSet;
     }
 
-    private class JPAEdmEntityType extends JPAEntityTypeMock<String> {
-      @Override
-      public String getName() {
-        return "SalesOrderHeader";
-      }
+    @SuppressWarnings("unchecked")
+    @Override
+    public <X> EntityType<X> entity(final Class<X> arg0) {
+      JPAEdmRefEntityType<String> refEntityType = new JPAEdmRefEntityType<String>();
+      return (EntityType<X>) refEntityType;
+
+    }
+  }
+
+  @SuppressWarnings("hiding")
+  private static class JPAEdmRefEntityType<String> extends JPAEntityTypeMock<String> {
+    Set<Attribute<? super String, ?>> attributeSet = new HashSet<Attribute<? super String, ?>>();
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+    private void setValuesToSet() {
+      attributeSet.add((Attribute<? super String, String>) new JPAEdmAttribute(java.lang.String.class, "SOLITID"));
+      attributeSet.add((Attribute<? super String, String>) new JPAEdmAttribute(java.lang.String.class, "SONAME"));
+    }
+
+    @Override
+    public Set<Attribute<? super String, ?>> getAttributes() {
+      setValuesToSet();
+      return attributeSet;
+    }
+
+    @Override
+    public java.lang.String getName() {
+      return "salesorderitemdetails";
     }
   }
 
   @SuppressWarnings("hiding")
-  private class JPAEdmEntityType<String> extends JPAEntityTypeMock<String> {
+  private static class JPAEdmEntityType<String> extends JPAEntityTypeMock<String> {
     Set<Attribute<? super String, ?>> attributeSet = new HashSet<Attribute<? super String, ?>>();
 
     @SuppressWarnings({ "unchecked", "rawtypes" })
@@ -306,6 +428,16 @@ public class JPAEdmPropertyTest extends JPAEdmTestModelView {
     }
 
     private class JPAEdmPluralAttribute extends JPAPluralAttributeMock {
+
+      @Override
+      public Member getJavaMember() {
+        if (ATTRIBUTE_TYPE.equals(PersistentAttributeType.MANY_TO_ONE)) {
+          return new JPAJavaMember();
+        }
+        return null;
+
+      }
+
       @Override
       public java.lang.String getName() {
         return "salesorderheaderdetails";
@@ -338,38 +470,6 @@ public class JPAEdmPropertyTest extends JPAEdmTestModelView {
         };
       }
     }
-
-    private class JPAEdmAttribute<Object, String> extends JPASingularAttributeMock<Object, String> {
-
-      @Override
-      public PersistentAttributeType getPersistentAttributeType() {
-        return ATTRIBUTE_TYPE;
-      }
-
-      Class<String> clazz;
-      java.lang.String attributeName;
-
-      public JPAEdmAttribute(final Class<String> javaType, final java.lang.String name) {
-        this.clazz = javaType;
-        this.attributeName = name;
-
-      }
-
-      @Override
-      public Class<String> getJavaType() {
-        return clazz;
-      }
-
-      @Override
-      public java.lang.String getName() {
-        return this.attributeName;
-      }
-
-      @Override
-      public boolean isId() {
-        return true;
-      }
-    }
   }
 
   @SuppressWarnings("hiding")
@@ -435,4 +535,46 @@ public class JPAEdmPropertyTest extends JPAEdmTestModelView {
 
   }
 
+  private static class JPAJavaMember extends JPAJavaMemberMock {
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <T extends Annotation> T getAnnotation(final Class<T> annotationClass) {
+
+      if (annotationClass.equals(JoinColumn.class)) {
+
+        if (testCase.equals("Default")) {
+          JoinColumn joinColumn = EasyMock.createMock(JoinColumn.class);
+          EasyMock.expect(joinColumn.name()).andReturn("FSOID").anyTimes();
+          EasyMock.expect(joinColumn.referencedColumnName()).andReturn("SOLITID").anyTimes();
+          EasyMock.expect(joinColumn.insertable()).andReturn(true).anyTimes();
+          EasyMock.expect(joinColumn.updatable()).andReturn(true).anyTimes();
+          EasyMock.replay(joinColumn);
+          return (T) joinColumn;
+        } else if (testCase.equals("NoJoinColumnNames")) {
+          JoinColumn joinColumn = EasyMock.createMock(JoinColumn.class);
+          EasyMock.expect(joinColumn.name()).andReturn("").anyTimes();
+          EasyMock.expect(joinColumn.referencedColumnName()).andReturn("").anyTimes();
+          EasyMock.expect(joinColumn.insertable()).andReturn(true).anyTimes();
+          EasyMock.expect(joinColumn.updatable()).andReturn(true).anyTimes();
+          EasyMock.replay(joinColumn);
+          return (T) joinColumn;
+        }
+
+      } else {
+
+        if (testCase.equals("Default")) {
+          Column column = EasyMock.createMock(Column.class);
+          EasyMock.expect(column.name()).andReturn("SOLITID").anyTimes();
+          EasyMock.expect(column.nullable()).andReturn(true).anyTimes();
+          EasyMock.expect(column.length()).andReturn(30).anyTimes();
+          EasyMock.replay(column);
+          return (T) column;
+        }
+
+      }
+      return null;
+    }
+  }
+
 }