You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by nt...@apache.org on 2018/12/28 12:38:23 UTC

[2/4] cayenne git commit: CAY-2467 New type-aware Property API - update client cgen templates - update client tests

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-client/src/test/java/org/apache/cayenne/query/ClientExpressionIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/query/ClientExpressionIT.java b/cayenne-client/src/test/java/org/apache/cayenne/query/ClientExpressionIT.java
index d7a9836..1a345a6 100644
--- a/cayenne-client/src/test/java/org/apache/cayenne/query/ClientExpressionIT.java
+++ b/cayenne-client/src/test/java/org/apache/cayenne/query/ClientExpressionIT.java
@@ -65,7 +65,7 @@ public class ClientExpressionIT extends ClientCase {
         tMtTable2.setColumns("TABLE2_ID", "TABLE1_ID", "GLOBAL_ATTRIBUTE");
     }
     
-    protected void createDataSet() throws Exception {
+    private void createDataSet() throws Exception {
         for(int i = 1; i <= 10; i++) {
             tMtTable1.insert(i ,"1_global" + i, "server" + i);
             tMtTable2.insert(i , i, "2_global" + i);
@@ -74,7 +74,7 @@ public class ClientExpressionIT extends ClientCase {
     }
 
     @Test
-    public void testPersistentValueInExpression() throws Exception {
+    public void testPersistentValueInExpression() {
         ClientMtTable1 t1 = context.newObject(ClientMtTable1.class);
         ClientMtTable1 t2 = context.newObject(ClientMtTable1.class);
         
@@ -89,18 +89,18 @@ public class ClientExpressionIT extends ClientCase {
     }
 
     @Test
-    public void testListInASTList() throws Exception {
+    public void testListInASTList() {
         ClientMtTable1 t1 = context.newObject(ClientMtTable1.class);
         ClientMtTable1 t2 = context.newObject(ClientMtTable1.class);
         
         context.commitChanges();
         
-        List<ClientMtTable1> table1List = new ArrayList<ClientMtTable1>();
+        List<ClientMtTable1> table1List = new ArrayList<>();
         table1List.add(t1);
         table1List.add(t2);
         
         // send list in expression factory
-        Expression list = ExpressionFactory.inExp(ClientMtTable2.TABLE1_PROPERTY, table1List);
+        Expression list = ClientMtTable2.TABLE1.in(table1List);
         
         Object[] values = (Object[])((ASTList)list.getOperand(1)).getOperand(0);
         assertEquals(t1.getObjectId(), values[0]);
@@ -117,19 +117,19 @@ public class ClientExpressionIT extends ClientCase {
     }
 
     @Test
-    public void testArrayInASTList() throws Exception {
+    public void testArrayInASTList() {
         ClientMtTable1 t1 = context.newObject(ClientMtTable1.class);
         ClientMtTable1 t2 = context.newObject(ClientMtTable1.class);
         ClientMtTable1 t3 = context.newObject(ClientMtTable1.class);
         
         context.commitChanges();
-        
+
         Object[] tArray = new Object[3];
         tArray[0] = t1;
         tArray[1] = t2;
         
         // send array in expression factory
-        Expression list = ExpressionFactory.inExp(ClientMtTable2.TABLE1_PROPERTY, tArray);
+        Expression list = ExpressionFactory.inExp(ClientMtTable2.TABLE1.getName(), tArray);
         tArray[2] = t3;
         
         Object[] values = (Object[])((ASTList)list.getOperand(1)).getOperand(0);
@@ -151,25 +151,25 @@ public class ClientExpressionIT extends ClientCase {
     @Test
     public void testExpressionFactoryMatch() throws Exception {
         createDataSet();
-        
-        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<ClientMtTable1>(ClientMtTable1.class);
+
+        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<>(ClientMtTable1.class);
         table1Query.addOrdering(new Ordering("db:TABLE1_ID", SortOrder.ASCENDING));
-        List<ClientMtTable1> table1List = context.select(table1Query);
-        
+        List<ClientMtTable1> table1List = table1Query.select(context);
+
         assertNotNull(table1List);
-        
+
         ClientMtTable1 element_1 = table1List.get(0);
         ClientMtTable1 element_2 = table1List.get(1);
-        
-        Expression exp = ExpressionFactory.matchExp(ClientMtTable2.TABLE1_PROPERTY, element_1);
-        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
-        List<ClientMtTable2> table2List = context.select(table2Query);
-        
+
+        Expression exp = ClientMtTable2.TABLE1.eq(element_1);
+        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
+        List<ClientMtTable2> table2List = table2Query.select(context);
+
         assertNotNull(table2List);
         assertEquals(2, table2List.size());
-        
+
         exp = ExpressionFactory.matchExp(element_2);
-        table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         table2List = context.select(table2Query);
 
         assertNotNull(table2List);
@@ -180,7 +180,7 @@ public class ClientExpressionIT extends ClientCase {
     public void testExpressionFactoryMatchAll() throws Exception {
         createDataSet();
         
-        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class);
+        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<>(ClientMtTable2.class);
         table2Query.addOrdering(new Ordering("db:TABLE2_ID", SortOrder.ASCENDING));
         List<ClientMtTable2> table2List = context.select(table2Query);
         
@@ -189,9 +189,9 @@ public class ClientExpressionIT extends ClientCase {
         
         assertEquals(element_1.getTable1(), element_2.getTable1());
         
-        Expression exp = ExpressionFactory.matchAllExp("|"+ClientMtTable1.TABLE2ARRAY_PROPERTY, Arrays.asList(element_1, element_2));
-        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<ClientMtTable1>(ClientMtTable1.class, exp);
-        List<ClientMtTable1> table1List = context.select(table1Query);
+        Expression exp = ExpressionFactory.matchAllExp("|"+ClientMtTable1.TABLE2ARRAY.getName(), Arrays.asList(element_1, element_2));
+        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<>(ClientMtTable1.class, exp);
+        List<ClientMtTable1> table1List = table1Query.select(context);
         
         assertEquals(1, table1List.size());
     }
@@ -200,7 +200,7 @@ public class ClientExpressionIT extends ClientCase {
     public void testExpressionFactoryMatchAny() throws Exception {
         createDataSet();
         
-        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class);
+        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<>(ClientMtTable2.class);
         table2Query.addOrdering(new Ordering("db:TABLE2_ID", SortOrder.ASCENDING));
         List<ClientMtTable2> table2List = context.select(table2Query);
         
@@ -208,7 +208,7 @@ public class ClientExpressionIT extends ClientCase {
         ClientMtTable2 element_2 = table2List.get(10);
         
         Expression exp = ExpressionFactory.matchAnyExp(element_1, element_2);
-        table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         table2List = context.select(table2Query);
         
         assertEquals(2, table2List.size());
@@ -218,7 +218,7 @@ public class ClientExpressionIT extends ClientCase {
     public void testExpressionFactoryIn() throws Exception {
         createDataSet();
         
-        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<ClientMtTable1>(ClientMtTable1.class);
+        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<>(ClientMtTable1.class);
         table1Query.addOrdering(new Ordering("db:TABLE1_ID", SortOrder.ASCENDING));
         List<ClientMtTable1> table1List = context.select(table1Query);
         
@@ -226,15 +226,15 @@ public class ClientExpressionIT extends ClientCase {
         ClientMtTable1 element_8 = table1List.get(7);
         
         // IN expression via Collection
-        Expression exp = ExpressionFactory.inExp(ClientMtTable2.TABLE1_PROPERTY, table1List.subList(3, 6));
-        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        Expression exp = ExpressionFactory.inExp(ClientMtTable2.TABLE1.getName(), table1List.subList(3, 6));
+        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         List<ClientMtTable2> table2List = context.select(table2Query);
         
         assertEquals(6, table2List.size());
         
         // IN expression via Array
-        exp = ExpressionFactory.inExp(ClientMtTable2.TABLE1_PROPERTY, element_3, element_8);
-        table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        exp = ExpressionFactory.inExp(ClientMtTable2.TABLE1.getName(), element_3, element_8);
+        table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         table2List = context.select(table2Query);
         
         assertEquals(4, table2List.size());
@@ -244,7 +244,7 @@ public class ClientExpressionIT extends ClientCase {
     public void testExpressionFactoryBetween() throws Exception {
         createDataSet();
         
-        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<ClientMtTable1>(ClientMtTable1.class);
+        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<>(ClientMtTable1.class);
         table1Query.addOrdering(new Ordering("db:TABLE1_ID", SortOrder.ASCENDING));
         List<ClientMtTable1> table1List = context.select(table1Query);
         
@@ -252,15 +252,15 @@ public class ClientExpressionIT extends ClientCase {
         ClientMtTable1 element_7 = table1List.get(6);
         
         // between
-        Expression exp = ExpressionFactory.betweenExp(ClientMtTable2.TABLE1_PROPERTY, element_1, element_7);
-        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        Expression exp = ExpressionFactory.betweenExp(ClientMtTable2.TABLE1.getName(), element_1, element_7);
+        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         List<ClientMtTable2> table2List = context.select(table2Query);
         
         assertEquals(14, table2List.size());
         
         // not between
-        exp = ExpressionFactory.notBetweenExp(ClientMtTable2.TABLE1_PROPERTY, element_1, element_7);
-        table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        exp = ExpressionFactory.notBetweenExp(ClientMtTable2.TABLE1.getName(), element_1, element_7);
+        table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         table2List = context.select(table2Query);
         
         assertEquals(6, table2List.size());
@@ -270,36 +270,36 @@ public class ClientExpressionIT extends ClientCase {
     public void testExpressionFactoryOperators() throws Exception {
         createDataSet();
         
-        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<ClientMtTable1>(ClientMtTable1.class);
+        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<>(ClientMtTable1.class);
         table1Query.addOrdering(new Ordering("db:TABLE1_ID", SortOrder.ASCENDING));
         List<ClientMtTable1> table1List = context.select(table1Query);
         
         ClientMtTable1 element_7 = table1List.get(6);
         
         // greater than, ">"
-        Expression exp = ExpressionFactory.greaterExp(ClientMtTable2.TABLE1_PROPERTY, element_7);
-        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        Expression exp = ExpressionFactory.greaterExp(ClientMtTable2.TABLE1.getName(), element_7);
+        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         List<ClientMtTable2> table2List = context.select(table2Query);
         
         assertEquals(6, table2List.size());
         
         // greater than or equal, ">="
-        exp = ExpressionFactory.greaterOrEqualExp(ClientMtTable2.TABLE1_PROPERTY, element_7);
-        table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        exp = ExpressionFactory.greaterOrEqualExp(ClientMtTable2.TABLE1.getName(), element_7);
+        table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         table2List = context.select(table2Query);
         
         assertEquals(8, table2List.size());
         
         // less than, "<"
-        exp = ExpressionFactory.lessExp(ClientMtTable2.TABLE1_PROPERTY, element_7);
-        table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        exp = ExpressionFactory.lessExp(ClientMtTable2.TABLE1.getName(), element_7);
+        table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         table2List = context.select(table2Query);
         
         assertEquals(12, table2List.size());
         
         // less than or equal, "<="
-        exp = ExpressionFactory.lessOrEqualExp(ClientMtTable2.TABLE1_PROPERTY, element_7);
-        table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        exp = ExpressionFactory.lessOrEqualExp(ClientMtTable2.TABLE1.getName(), element_7);
+        table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         table2List = context.select(table2Query);
         
         assertEquals(14, table2List.size());
@@ -309,7 +309,7 @@ public class ClientExpressionIT extends ClientCase {
     public void testParams() throws Exception {
         createDataSet();
         
-        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<ClientMtTable1>(ClientMtTable1.class);
+        SelectQuery<ClientMtTable1> table1Query = new SelectQuery<>(ClientMtTable1.class);
         table1Query.addOrdering(new Ordering("db:TABLE1_ID", SortOrder.ASCENDING));
         List<ClientMtTable1> table1List = context.select(table1Query);
         
@@ -318,13 +318,13 @@ public class ClientExpressionIT extends ClientCase {
         
         Expression exp = ExpressionFactory.exp("table1 = $attr");
         exp = exp.params(Collections.singletonMap("attr", element_1));
-        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        SelectQuery<ClientMtTable2> table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         List<ClientMtTable2> table2List = context.select(table2Query);
         
         assertEquals(2, table2List.size());
         
         exp = exp.andExp(ExpressionFactory.exp("table1 = $attr")).params(Collections.singletonMap("attr", element_5));
-        table2Query = new SelectQuery<ClientMtTable2>(ClientMtTable2.class, exp);
+        table2Query = new SelectQuery<>(ClientMtTable2.class, exp);
         table2List = context.select(table2Query);
         
         assertEquals(0, table2List.size());

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-client/src/test/java/org/apache/cayenne/query/ClientSelectQueryExpressionIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/query/ClientSelectQueryExpressionIT.java b/cayenne-client/src/test/java/org/apache/cayenne/query/ClientSelectQueryExpressionIT.java
index 3d0c05a..5ccdea2 100644
--- a/cayenne-client/src/test/java/org/apache/cayenne/query/ClientSelectQueryExpressionIT.java
+++ b/cayenne-client/src/test/java/org/apache/cayenne/query/ClientSelectQueryExpressionIT.java
@@ -21,7 +21,6 @@ package org.apache.cayenne.query;
 import org.apache.cayenne.CayenneContext;
 import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.exp.Expression;
-import org.apache.cayenne.exp.ExpressionFactory;
 import org.apache.cayenne.test.jdbc.DBHelper;
 import org.apache.cayenne.test.jdbc.TableHelper;
 import org.apache.cayenne.testdo.mt.ClientMtTable1;
@@ -52,7 +51,7 @@ public class ClientSelectQueryExpressionIT extends ClientCase {
         tMtTable1.setColumns("TABLE1_ID", "GLOBAL_ATTRIBUTE1", "SERVER_ATTRIBUTE1");
     }
 
-    protected void createMtTable1DataSet() throws Exception {
+    private void createMtTable1DataSet() throws Exception {
         for (int i = 1; i <= 20; i++) {
             tMtTable1.insert(i, "globalAttr" + i, "serverAttr" + i);
         }
@@ -64,7 +63,7 @@ public class ClientSelectQueryExpressionIT extends ClientCase {
 
         List<ClientMtTable1> mtTable1List = context.select(SelectQuery.query(ClientMtTable1.class));
 
-        Expression exp = ExpressionFactory.likeExp(ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, "globalAttr1%");
+        Expression exp = ClientMtTable1.GLOBAL_ATTRIBUTE1.like("globalAttr1%");
         exp.filterObjects(mtTable1List);
 
         List<ClientMtTable1> matchingMtTableList = context.select(SelectQuery.query(ClientMtTable1.class, exp));

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-client/src/test/java/org/apache/cayenne/remote/ClientChannelServerDiffsIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/remote/ClientChannelServerDiffsIT.java b/cayenne-client/src/test/java/org/apache/cayenne/remote/ClientChannelServerDiffsIT.java
index 4c3b79b..1bfdb24 100644
--- a/cayenne-client/src/test/java/org/apache/cayenne/remote/ClientChannelServerDiffsIT.java
+++ b/cayenne-client/src/test/java/org/apache/cayenne/remote/ClientChannelServerDiffsIT.java
@@ -103,7 +103,7 @@ public class ClientChannelServerDiffsIT extends ClientCase {
     @Test
     public void testReturnDiffInPrePersist() {
 
-        final List<GenericDiff> diffs = new ArrayList<GenericDiff>();
+        final List<GenericDiff> diffs = new ArrayList<>();
         final NoopGraphChangeHandler diffReader = new NoopGraphChangeHandler() {
 
             @Override
@@ -168,7 +168,7 @@ public class ClientChannelServerDiffsIT extends ClientCase {
             assertEquals(2, diffReader.size);
             assertEquals(1, diffs.size());
             assertEquals(tempId, diffs.get(0).sourceId);
-            assertEquals(ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, diffs.get(0).property);
+            assertEquals(ClientMtTable1.GLOBAL_ATTRIBUTE1.getName(), diffs.get(0).property);
             assertNull(diffs.get(0).oldValue);
             assertEquals("XXX", diffs.get(0).newValue);
         }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-client/src/test/java/org/apache/cayenne/remote/RemoteIncrementalFaultListIT.java
----------------------------------------------------------------------
diff --git a/cayenne-client/src/test/java/org/apache/cayenne/remote/RemoteIncrementalFaultListIT.java b/cayenne-client/src/test/java/org/apache/cayenne/remote/RemoteIncrementalFaultListIT.java
index c5df3a6..3d7fb3a 100644
--- a/cayenne-client/src/test/java/org/apache/cayenne/remote/RemoteIncrementalFaultListIT.java
+++ b/cayenne-client/src/test/java/org/apache/cayenne/remote/RemoteIncrementalFaultListIT.java
@@ -23,7 +23,6 @@ import org.apache.cayenne.CayenneContext;
 import org.apache.cayenne.Persistent;
 import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.exp.Expression;
-import org.apache.cayenne.exp.ExpressionFactory;
 import org.apache.cayenne.query.SelectQuery;
 import org.apache.cayenne.query.SortOrder;
 import org.apache.cayenne.test.jdbc.DBHelper;
@@ -68,7 +67,7 @@ public class RemoteIncrementalFaultListIT extends ClientCase {
 				"SERVER_ATTRIBUTE1");
 	}
 
-	protected void createObjectsDataSet() throws Exception {
+	private void createObjectsDataSet() throws Exception {
 		tMTTable.insert(1, "g1", "s1");
 		tMTTable.insert(2, "g2", "s2");
 		tMTTable.insert(3, "g3", "s3");
@@ -100,14 +99,12 @@ public class RemoteIncrementalFaultListIT extends ClientCase {
 
 		createObjectsDataSet();
 
-		SelectQuery<ClientMtTable1> query = new SelectQuery<ClientMtTable1>(
-				ClientMtTable1.class);
+		SelectQuery<ClientMtTable1> query = new SelectQuery<>(ClientMtTable1.class);
 
 		// make sure total number of objects is not divisable
 		// by the page size, to test the last smaller page
 		query.setPageSize(pageSize);
-		query.addOrdering("db:" + MtTable1.TABLE1_ID_PK_COLUMN,
-				SortOrder.ASCENDING);
+		query.addOrdering("db:" + MtTable1.TABLE1_ID_PK_COLUMN, SortOrder.ASCENDING);
 
 		list = new RemoteIncrementalFaultList(clientContext, query);
 	}
@@ -161,14 +158,12 @@ public class RemoteIncrementalFaultListIT extends ClientCase {
 			assertTrue(obj instanceof Persistent);
 
 			// iterator must be resolved page by page
-			int expectedResolved = list.pageIndex(counter) * list.getPageSize()
-					+ list.getPageSize();
+			int expectedResolved = list.pageIndex(counter) * list.getPageSize() + list.getPageSize();
 			if (expectedResolved > list.size()) {
 				expectedResolved = list.size();
 			}
 
-			assertEquals(list.size() - expectedResolved,
-					list.getUnfetchedObjects());
+			assertEquals(list.size() - expectedResolved, list.getUnfetchedObjects());
 
 			counter++;
 		}
@@ -229,35 +224,29 @@ public class RemoteIncrementalFaultListIT extends ClientCase {
 	public void testIndexOf() throws Exception {
 		prepareList(6);
 
-		Expression qual = ExpressionFactory.matchExp(
-				ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, "g20");
-		SelectQuery<ClientMtTable1> query = new SelectQuery<ClientMtTable1>(
-				ClientMtTable1.class, qual);
+		Expression qual = ClientMtTable1.GLOBAL_ATTRIBUTE1.eq("g20");
+		SelectQuery<ClientMtTable1> query = new SelectQuery<>(ClientMtTable1.class, qual);
 		List<?> artists = list.context.performQuery(query);
 
 		assertEquals(1, artists.size());
 
 		ClientMtTable1 row = (ClientMtTable1) artists.get(0);
 		assertEquals(19, list.indexOf(row));
-		assertEquals(-1,
-				list.indexOf(list.context.newObject(ClientMtTable1.class)));
+		assertEquals(-1, list.indexOf(list.context.newObject(ClientMtTable1.class)));
 	}
 
 	@Test
 	public void testLastIndexOf() throws Exception {
 		prepareList(6);
-		Expression qual = ExpressionFactory.matchExp(
-				ClientMtTable1.GLOBAL_ATTRIBUTE1_PROPERTY, "g20");
-		SelectQuery<ClientMtTable1> query = new SelectQuery<ClientMtTable1>(
-				ClientMtTable1.class, qual);
+		Expression qual = ClientMtTable1.GLOBAL_ATTRIBUTE1.eq("g20");
+		SelectQuery<ClientMtTable1> query = new SelectQuery<>(ClientMtTable1.class, qual);
 		List<?> objects = list.context.performQuery(query);
 
 		assertEquals(1, objects.size());
 
 		ClientMtTable1 row = (ClientMtTable1) objects.get(0);
 		assertEquals(19, list.lastIndexOf(row));
-		assertEquals(-1,
-				list.lastIndexOf(list.context.newObject(ClientMtTable1.class)));
+		assertEquals(-1, list.lastIndexOf(list.context.newObject(ClientMtTable1.class)));
 	}
 
 	private void doTestIterator(int size) throws Exception {

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_ClientMtTable1.java
----------------------------------------------------------------------
diff --git a/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_ClientMtTable1.java b/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_ClientMtTable1.java
index e699ccf..9e36772 100644
--- a/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_ClientMtTable1.java
+++ b/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_ClientMtTable1.java
@@ -7,7 +7,10 @@ import java.util.Date;
 import java.util.List;
 
 import org.apache.cayenne.PersistentObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.DateProperty;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.rop.protostuff.persistent.ClientMtTable2;
 import org.apache.cayenne.util.PersistentObjectList;
 
@@ -18,13 +21,13 @@ import org.apache.cayenne.util.PersistentObjectList;
  */
 public abstract class _ClientMtTable1 extends PersistentObject {
 
-    public static final Property<LocalDate> DATE_ATTRIBUTE = Property.create("dateAttribute", LocalDate.class);
-    public static final Property<String> GLOBAL_ATTRIBUTE = Property.create("globalAttribute", String.class);
-    public static final Property<Date> OLD_DATE_ATTRIBUTE = Property.create("oldDateAttribute", Date.class);
-    public static final Property<String> SERVER_ATTRIBUTE = Property.create("serverAttribute", String.class);
-    public static final Property<LocalTime> TIME_ATTRIBUTE = Property.create("timeAttribute", LocalTime.class);
-    public static final Property<LocalDateTime> TIMESTAMP_ATTRIBUTE = Property.create("timestampAttribute", LocalDateTime.class);
-    public static final Property<List<ClientMtTable2>> TABLE2ARRAY = Property.create("table2Array", List.class);
+    public static final DateProperty<LocalDate> DATE_ATTRIBUTE = PropertyFactory.createDate("dateAttribute", LocalDate.class);
+    public static final StringProperty<String> GLOBAL_ATTRIBUTE = PropertyFactory.createString("globalAttribute", String.class);
+    public static final DateProperty<Date> OLD_DATE_ATTRIBUTE = PropertyFactory.createDate("oldDateAttribute", Date.class);
+    public static final StringProperty<String> SERVER_ATTRIBUTE = PropertyFactory.createString("serverAttribute", String.class);
+    public static final DateProperty<LocalTime> TIME_ATTRIBUTE = PropertyFactory.createDate("timeAttribute", LocalTime.class);
+    public static final DateProperty<LocalDateTime> TIMESTAMP_ATTRIBUTE = PropertyFactory.createDate("timestampAttribute", LocalDateTime.class);
+    public static final ListProperty<ClientMtTable2> TABLE2ARRAY = PropertyFactory.createList("table2Array", ClientMtTable2.class);
 
     protected LocalDate dateAttribute;
     protected String globalAttribute;

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_ClientMtTable2.java
----------------------------------------------------------------------
diff --git a/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_ClientMtTable2.java b/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_ClientMtTable2.java
index 6128e40..6020a3e 100644
--- a/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_ClientMtTable2.java
+++ b/cayenne-protostuff/src/test/java/org/apache/cayenne/rop/protostuff/persistent/auto/_ClientMtTable2.java
@@ -2,7 +2,9 @@ package org.apache.cayenne.rop.protostuff.persistent.auto;
 
 import org.apache.cayenne.PersistentObject;
 import org.apache.cayenne.ValueHolder;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.EntityProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.rop.protostuff.persistent.ClientMtTable1;
 import org.apache.cayenne.util.PersistentObjectHolder;
 
@@ -13,8 +15,8 @@ import org.apache.cayenne.util.PersistentObjectHolder;
  */
 public abstract class _ClientMtTable2 extends PersistentObject {
 
-    public static final Property<String> GLOBAL_ATTRIBUTE = Property.create("globalAttribute", String.class);
-    public static final Property<ClientMtTable1> TABLE1 = Property.create("table1", ClientMtTable1.class);
+    public static final StringProperty<String> GLOBAL_ATTRIBUTE = PropertyFactory.createString("globalAttribute", String.class);
+    public static final EntityProperty<ClientMtTable1> TABLE1 = PropertyFactory.createEntity("table1", ClientMtTable1.class);
 
     protected String globalAttribute;
     protected ValueHolder<ClientMtTable1> table1;
@@ -49,7 +51,6 @@ public abstract class _ClientMtTable2 extends PersistentObject {
     public void setTable1(ClientMtTable1 table1) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table1", true);
-            objectContext.propertyChanged(this, "table1", this.table1.getValueDirectly(), table1);
         } else if (this.table1 == null) {
         	this.table1 = new PersistentObjectHolder<>(this, "table1");
 		}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-server/src/test/java/org/apache/cayenne/access/EmbeddingIT.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/access/EmbeddingIT.java b/cayenne-server/src/test/java/org/apache/cayenne/access/EmbeddingIT.java
index 9675a0c..883bca0 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/access/EmbeddingIT.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/access/EmbeddingIT.java
@@ -23,6 +23,9 @@ import org.apache.cayenne.DataRow;
 import org.apache.cayenne.ObjectContext;
 import org.apache.cayenne.PersistenceState;
 import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.exp.Expression;
+import org.apache.cayenne.exp.ExpressionFactory;
+import org.apache.cayenne.query.ObjectSelect;
 import org.apache.cayenne.query.SelectQuery;
 import org.apache.cayenne.test.jdbc.DBHelper;
 import org.apache.cayenne.test.jdbc.TableHelper;
@@ -105,6 +108,20 @@ public class EmbeddingIT extends ServerCase {
     }
 
     @Test
+    public void testEmbeddableInWhere() throws Exception {
+        createSelectDataSet();
+
+        Embeddable1 embeddable1 = new Embeddable1();
+        embeddable1.setEmbedded10("e1");
+        embeddable1.setEmbedded20("e2");
+
+        Expression exp = ExpressionFactory.matchDbExp(Embeddable1.EMBEDDED10.getName().toUpperCase(), "e1");
+
+
+        ObjectSelect.query(EmbedEntity1.class).where(exp).select(context);
+    }
+
+    @Test
     public void testInsert() throws Exception {
 
         EmbedEntity1 o1 = context.newObject(EmbedEntity1.class);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1.java
index 8178b9d..e249272 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1.java
@@ -3,7 +3,11 @@ package org.apache.cayenne.testdo.mt.auto;
 import java.util.List;
 
 import org.apache.cayenne.PersistentObject;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.testdo.mt.ClientMtTable2;
+import org.apache.cayenne.util.PersistentObjectList;
 
 /**
  * A generated persistent class mapped as "MtTable1" Cayenne entity. It is a good idea to
@@ -12,9 +16,9 @@ import org.apache.cayenne.testdo.mt.ClientMtTable2;
  */
 public abstract class _ClientMtTable1 extends PersistentObject {
 
-    public static final String GLOBAL_ATTRIBUTE1_PROPERTY = "globalAttribute1";
-    public static final String SERVER_ATTRIBUTE1_PROPERTY = "serverAttribute1";
-    public static final String TABLE2ARRAY_PROPERTY = "table2Array";
+    public static final StringProperty<String> GLOBAL_ATTRIBUTE1 = PropertyFactory.createString("globalAttribute1", String.class);
+    public static final StringProperty<String> SERVER_ATTRIBUTE1 = PropertyFactory.createString("serverAttribute1", String.class);
+    public static final ListProperty<ClientMtTable2> TABLE2ARRAY = PropertyFactory.createList("table2Array", ClientMtTable2.class);
 
     protected String globalAttribute1;
     protected String serverAttribute1;
@@ -27,18 +31,14 @@ public abstract class _ClientMtTable1 extends PersistentObject {
 
         return globalAttribute1;
     }
+
     public void setGlobalAttribute1(String globalAttribute1) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "globalAttribute1", false);
+            objectContext.propertyChanged(this, "globalAttribute1", this.globalAttribute1, globalAttribute1);
         }
 
-        Object oldValue = this.globalAttribute1;
         this.globalAttribute1 = globalAttribute1;
-
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "globalAttribute1", oldValue, globalAttribute1);
-        }
     }
 
     public String getServerAttribute1() {
@@ -48,38 +48,42 @@ public abstract class _ClientMtTable1 extends PersistentObject {
 
         return serverAttribute1;
     }
+
     public void setServerAttribute1(String serverAttribute1) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "serverAttribute1", false);
+            objectContext.propertyChanged(this, "serverAttribute1", this.serverAttribute1, serverAttribute1);
         }
 
-        Object oldValue = this.serverAttribute1;
         this.serverAttribute1 = serverAttribute1;
-
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "serverAttribute1", oldValue, serverAttribute1);
-        }
     }
 
     public List<ClientMtTable2> getTable2Array() {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table2Array", true);
-        }
+        } else if (this.table2Array == null) {
+        	this.table2Array = new PersistentObjectList<>(this, "table2Array");
+		}
 
         return table2Array;
     }
+
     public void addToTable2Array(ClientMtTable2 object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table2Array", true);
-        }
+        } else if (this.table2Array == null) {
+        	this.table2Array = new PersistentObjectList<>(this, "table2Array");
+		}
 
         this.table2Array.add(object);
     }
+
     public void removeFromTable2Array(ClientMtTable2 object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table2Array", true);
-        }
+        } else if (this.table2Array == null) {
+        	this.table2Array = new PersistentObjectList<>(this, "table2Array");
+		}
 
         this.table2Array.remove(object);
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1Subclass1.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1Subclass1.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1Subclass1.java
index 259af58..b54bf1b 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1Subclass1.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1Subclass1.java
@@ -1,6 +1,7 @@
 package org.apache.cayenne.testdo.mt.auto;
 
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.testdo.mt.ClientMtTable1;
 
 /**
@@ -10,10 +11,7 @@ import org.apache.cayenne.testdo.mt.ClientMtTable1;
  */
 public abstract class _ClientMtTable1Subclass1 extends ClientMtTable1 {
 
-    @Deprecated
-    public static final String SUBCLASS1ATTRIBUTE1_PROPERTY = "subclass1Attribute1";
-
-    public static final Property<String> SUBCLASS1ATTRIBUTE1 = Property.create("subclass1Attribute1", String.class);
+    public static final StringProperty<String> SUBCLASS1ATTRIBUTE1 = PropertyFactory.createString("subclass1Attribute1", String.class);
 
     protected String subclass1Attribute1;
 
@@ -24,17 +22,13 @@ public abstract class _ClientMtTable1Subclass1 extends ClientMtTable1 {
 
         return subclass1Attribute1;
     }
+
     public void setSubclass1Attribute1(String subclass1Attribute1) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "subclass1Attribute1", false);
+            objectContext.propertyChanged(this, "subclass1Attribute1", this.subclass1Attribute1, subclass1Attribute1);
         }
 
-        Object oldValue = this.subclass1Attribute1;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "subclass1Attribute1", oldValue, subclass1Attribute1);
-        }
-        
         this.subclass1Attribute1 = subclass1Attribute1;
     }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1Subclass2.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1Subclass2.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1Subclass2.java
index eb29449..e4efeb5 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1Subclass2.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable1Subclass2.java
@@ -1,6 +1,7 @@
 package org.apache.cayenne.testdo.mt.auto;
 
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.testdo.mt.ClientMtTable1;
 
 /**
@@ -10,10 +11,7 @@ import org.apache.cayenne.testdo.mt.ClientMtTable1;
  */
 public abstract class _ClientMtTable1Subclass2 extends ClientMtTable1 {
 
-    @Deprecated
-    public static final String SUBCLASS2ATTRIBUTE1_PROPERTY = "subclass2Attribute1";
-
-    public static final Property<String> SUBCLASS2ATTRIBUTE1 = Property.create("subclass2Attribute1", String.class);
+    public static final StringProperty<String> SUBCLASS2ATTRIBUTE1 = PropertyFactory.createString("subclass2Attribute1", String.class);
 
     protected String subclass2Attribute1;
 
@@ -24,17 +22,13 @@ public abstract class _ClientMtTable1Subclass2 extends ClientMtTable1 {
 
         return subclass2Attribute1;
     }
+
     public void setSubclass2Attribute1(String subclass2Attribute1) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "subclass2Attribute1", false);
+            objectContext.propertyChanged(this, "subclass2Attribute1", this.subclass2Attribute1, subclass2Attribute1);
         }
 
-        Object oldValue = this.subclass2Attribute1;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "subclass2Attribute1", oldValue, subclass2Attribute1);
-        }
-        
         this.subclass2Attribute1 = subclass2Attribute1;
     }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable2.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable2.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable2.java
index a8ac1f5..77c9b60 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable2.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable2.java
@@ -2,8 +2,12 @@ package org.apache.cayenne.testdo.mt.auto;
 
 import org.apache.cayenne.PersistentObject;
 import org.apache.cayenne.ValueHolder;
+import org.apache.cayenne.exp.property.EntityProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.testdo.mt.ClientMtTable1;
 import org.apache.cayenne.testdo.mt.ClientMtTable3;
+import org.apache.cayenne.util.PersistentObjectHolder;
 
 /**
  * A generated persistent class mapped as "MtTable2" Cayenne entity. It is a good idea to
@@ -12,13 +16,13 @@ import org.apache.cayenne.testdo.mt.ClientMtTable3;
  */
 public abstract class _ClientMtTable2 extends PersistentObject {
 
-    public static final String GLOBAL_ATTRIBUTE_PROPERTY = "globalAttribute";
-    public static final String TABLE1_PROPERTY = "table1";
-    public static final String TABLE3_PROPERTY = "table3";
+    public static final StringProperty<String> GLOBAL_ATTRIBUTE = PropertyFactory.createString("globalAttribute", String.class);
+    public static final EntityProperty<ClientMtTable1> TABLE1 = PropertyFactory.createEntity("table1", ClientMtTable1.class);
+    public static final EntityProperty<ClientMtTable3> TABLE3 = PropertyFactory.createEntity("table3", ClientMtTable3.class);
 
     protected String globalAttribute;
-    protected ValueHolder table1;
-    protected ValueHolder table3;
+    protected ValueHolder<ClientMtTable1> table1;
+    protected ValueHolder<ClientMtTable3> table3;
 
     public String getGlobalAttribute() {
         if(objectContext != null) {
@@ -27,31 +31,32 @@ public abstract class _ClientMtTable2 extends PersistentObject {
 
         return globalAttribute;
     }
+
     public void setGlobalAttribute(String globalAttribute) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "globalAttribute", false);
+            objectContext.propertyChanged(this, "globalAttribute", this.globalAttribute, globalAttribute);
         }
 
-        Object oldValue = this.globalAttribute;
         this.globalAttribute = globalAttribute;
-
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "globalAttribute", oldValue, globalAttribute);
-        }
     }
 
     public ClientMtTable1 getTable1() {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table1", true);
-        }
+        } else if (this.table1 == null) {
+        	this.table1 = new PersistentObjectHolder<>(this, "table1");
+		}
 
-        return (ClientMtTable1) table1.getValue();
+        return table1.getValue();
     }
+
     public void setTable1(ClientMtTable1 table1) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table1", true);
-        }
+        } else if (this.table1 == null) {
+        	this.table1 = new PersistentObjectHolder<>(this, "table1");
+		}
 
         this.table1.setValue(table1);
     }
@@ -59,14 +64,19 @@ public abstract class _ClientMtTable2 extends PersistentObject {
     public ClientMtTable3 getTable3() {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table3", true);
-        }
+        } else if (this.table3 == null) {
+        	this.table3 = new PersistentObjectHolder<>(this, "table3");
+		}
 
-        return (ClientMtTable3) table3.getValue();
+        return table3.getValue();
     }
+
     public void setTable3(ClientMtTable3 table3) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table3", true);
-        }
+        } else if (this.table3 == null) {
+        	this.table3 = new PersistentObjectHolder<>(this, "table3");
+		}
 
         this.table3.setValue(table3);
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable3.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable3.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable3.java
index cf84a87..e8e52c1 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable3.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable3.java
@@ -3,7 +3,13 @@ package org.apache.cayenne.testdo.mt.auto;
 import java.util.List;
 
 import org.apache.cayenne.PersistentObject;
+import org.apache.cayenne.exp.property.BaseProperty;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.NumericProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.testdo.mt.ClientMtTable2;
+import org.apache.cayenne.util.PersistentObjectList;
 
 /**
  * A generated persistent class mapped as "MtTable3" Cayenne entity. It is a good idea to
@@ -12,10 +18,10 @@ import org.apache.cayenne.testdo.mt.ClientMtTable2;
  */
 public abstract class _ClientMtTable3 extends PersistentObject {
 
-    public static final String BINARY_COLUMN_PROPERTY = "binaryColumn";
-    public static final String CHAR_COLUMN_PROPERTY = "charColumn";
-    public static final String INT_COLUMN_PROPERTY = "intColumn";
-    public static final String TABLE2ARRAY_PROPERTY = "table2Array";
+    public static final BaseProperty<byte[]> BINARY_COLUMN = PropertyFactory.createBase("binaryColumn", byte[].class);
+    public static final StringProperty<String> CHAR_COLUMN = PropertyFactory.createString("charColumn", String.class);
+    public static final NumericProperty<Integer> INT_COLUMN = PropertyFactory.createNumeric("intColumn", Integer.class);
+    public static final ListProperty<ClientMtTable2> TABLE2ARRAY = PropertyFactory.createList("table2Array", ClientMtTable2.class);
 
     protected byte[] binaryColumn;
     protected String charColumn;
@@ -29,18 +35,14 @@ public abstract class _ClientMtTable3 extends PersistentObject {
 
         return binaryColumn;
     }
+
     public void setBinaryColumn(byte[] binaryColumn) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "binaryColumn", false);
+            objectContext.propertyChanged(this, "binaryColumn", this.binaryColumn, binaryColumn);
         }
 
-        Object oldValue = this.binaryColumn;
         this.binaryColumn = binaryColumn;
-
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "binaryColumn", oldValue, binaryColumn);
-        }
     }
 
     public String getCharColumn() {
@@ -50,18 +52,14 @@ public abstract class _ClientMtTable3 extends PersistentObject {
 
         return charColumn;
     }
+
     public void setCharColumn(String charColumn) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "charColumn", false);
+            objectContext.propertyChanged(this, "charColumn", this.charColumn, charColumn);
         }
 
-        Object oldValue = this.charColumn;
         this.charColumn = charColumn;
-
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "charColumn", oldValue, charColumn);
-        }
     }
 
     public Integer getIntColumn() {
@@ -71,38 +69,42 @@ public abstract class _ClientMtTable3 extends PersistentObject {
 
         return intColumn;
     }
+
     public void setIntColumn(Integer intColumn) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "intColumn", false);
+            objectContext.propertyChanged(this, "intColumn", this.intColumn, intColumn);
         }
 
-        Object oldValue = this.intColumn;
         this.intColumn = intColumn;
-
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "intColumn", oldValue, intColumn);
-        }
     }
 
     public List<ClientMtTable2> getTable2Array() {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table2Array", true);
-        }
+        } else if (this.table2Array == null) {
+        	this.table2Array = new PersistentObjectList<>(this, "table2Array");
+		}
 
         return table2Array;
     }
+
     public void addToTable2Array(ClientMtTable2 object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table2Array", true);
-        }
+        } else if (this.table2Array == null) {
+        	this.table2Array = new PersistentObjectList<>(this, "table2Array");
+		}
 
         this.table2Array.add(object);
     }
+
     public void removeFromTable2Array(ClientMtTable2 object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table2Array", true);
-        }
+        } else if (this.table2Array == null) {
+        	this.table2Array = new PersistentObjectList<>(this, "table2Array");
+		}
 
         this.table2Array.remove(object);
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable4.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable4.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable4.java
index 92c6f1b..adeb8e4 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable4.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable4.java
@@ -3,7 +3,10 @@ package org.apache.cayenne.testdo.mt.auto;
 import java.util.List;
 
 import org.apache.cayenne.PersistentObject;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
 import org.apache.cayenne.testdo.mt.ClientMtTable5;
+import org.apache.cayenne.util.PersistentObjectList;
 
 /**
  * A generated persistent class mapped as "MtTable4" Cayenne entity. It is a good idea to
@@ -12,28 +15,36 @@ import org.apache.cayenne.testdo.mt.ClientMtTable5;
  */
 public abstract class _ClientMtTable4 extends PersistentObject {
 
-    public static final String TABLE5S_PROPERTY = "table5s";
+    public static final ListProperty<ClientMtTable5> TABLE5S = PropertyFactory.createList("table5s", ClientMtTable5.class);
 
     protected List<ClientMtTable5> table5s;
 
     public List<ClientMtTable5> getTable5s() {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table5s", true);
-        }
+        } else if (this.table5s == null) {
+        	this.table5s = new PersistentObjectList<>(this, "table5s");
+		}
 
         return table5s;
     }
+
     public void addToTable5s(ClientMtTable5 object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table5s", true);
-        }
+        } else if (this.table5s == null) {
+        	this.table5s = new PersistentObjectList<>(this, "table5s");
+		}
 
         this.table5s.add(object);
     }
+
     public void removeFromTable5s(ClientMtTable5 object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table5s", true);
-        }
+        } else if (this.table5s == null) {
+        	this.table5s = new PersistentObjectList<>(this, "table5s");
+		}
 
         this.table5s.remove(object);
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable5.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable5.java b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable5.java
index 3eb221c..17672a3 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable5.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/testdo/mt/auto/_ClientMtTable5.java
@@ -3,7 +3,10 @@ package org.apache.cayenne.testdo.mt.auto;
 import java.util.List;
 
 import org.apache.cayenne.PersistentObject;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
 import org.apache.cayenne.testdo.mt.ClientMtTable4;
+import org.apache.cayenne.util.PersistentObjectList;
 
 /**
  * A generated persistent class mapped as "MtTable5" Cayenne entity. It is a good idea to
@@ -12,28 +15,36 @@ import org.apache.cayenne.testdo.mt.ClientMtTable4;
  */
 public abstract class _ClientMtTable5 extends PersistentObject {
 
-    public static final String TABLE4S_PROPERTY = "table4s";
+    public static final ListProperty<ClientMtTable4> TABLE4S = PropertyFactory.createList("table4s", ClientMtTable4.class);
 
     protected List<ClientMtTable4> table4s;
 
     public List<ClientMtTable4> getTable4s() {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table4s", true);
-        }
+        } else if (this.table4s == null) {
+        	this.table4s = new PersistentObjectList<>(this, "table4s");
+		}
 
         return table4s;
     }
+
     public void addToTable4s(ClientMtTable4 object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table4s", true);
-        }
+        } else if (this.table4s == null) {
+        	this.table4s = new PersistentObjectList<>(this, "table4s");
+		}
 
         this.table4s.add(object);
     }
+
     public void removeFromTable4s(ClientMtTable4 object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "table4s", true);
-        }
+        } else if (this.table4s == null) {
+        	this.table4s = new PersistentObjectList<>(this, "table4s");
+		}
 
         this.table4s.remove(object);
     }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/cayenne-server/src/test/java/org/apache/cayenne/util/PersistentObjectHolderTest.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/test/java/org/apache/cayenne/util/PersistentObjectHolderTest.java b/cayenne-server/src/test/java/org/apache/cayenne/util/PersistentObjectHolderTest.java
index ca9080b..18a2519 100644
--- a/cayenne-server/src/test/java/org/apache/cayenne/util/PersistentObjectHolderTest.java
+++ b/cayenne-server/src/test/java/org/apache/cayenne/util/PersistentObjectHolderTest.java
@@ -41,7 +41,7 @@ public class PersistentObjectHolderTest {
         ClientMtTable2 o = new ClientMtTable2();
         o.setPersistenceState(PersistenceState.COMMITTED);
         o.setObjectContext(context);
-        PersistentObjectHolder holder = new PersistentObjectHolder(o, ClientMtTable2.TABLE1_PROPERTY);
+        PersistentObjectHolder holder = new PersistentObjectHolder(o, ClientMtTable2.TABLE1.getName());
 
         assertTrue(holder.isFault());
         ClientMtTable1 o1 = new ClientMtTable1();
@@ -59,7 +59,7 @@ public class PersistentObjectHolderTest {
         ClientMtTable2 o = new ClientMtTable2();
         o.setPersistenceState(PersistenceState.COMMITTED);
         o.setObjectContext(context);
-        PersistentObjectHolder holder = new PersistentObjectHolder(o, ClientMtTable2.TABLE1_PROPERTY);
+        PersistentObjectHolder holder = new PersistentObjectHolder(o, ClientMtTable2.TABLE1.getName());
 
         assertTrue(holder.isFault());
         ClientMtTable1 o1 = new ClientMtTable1();

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java b/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
index b478b8d..052709b 100644
--- a/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
+++ b/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
@@ -4,7 +4,10 @@ import java.time.LocalDate;
 import java.util.List;
 
 import org.apache.cayenne.PersistentObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.DateProperty;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.client.Painting;
 import org.apache.cayenne.util.PersistentObjectList;
 
@@ -15,9 +18,9 @@ import org.apache.cayenne.util.PersistentObjectList;
  */
 public abstract class _Artist extends PersistentObject {
 
-    public static final Property<LocalDate> DATE_OF_BIRTH = Property.create("dateOfBirth", LocalDate.class);
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<List<Painting>> PAINTINGS = Property.create("paintings", List.class);
+    public static final DateProperty<LocalDate> DATE_OF_BIRTH = PropertyFactory.createDate("dateOfBirth", LocalDate.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final ListProperty<Painting> PAINTINGS = PropertyFactory.createList("paintings", Painting.class);
 
     protected LocalDate dateOfBirth;
     protected String name;
@@ -30,17 +33,13 @@ public abstract class _Artist extends PersistentObject {
 
         return dateOfBirth;
     }
+
     public void setDateOfBirth(LocalDate dateOfBirth) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "dateOfBirth", false);
+            objectContext.propertyChanged(this, "dateOfBirth", this.dateOfBirth, dateOfBirth);
         }
 
-        Object oldValue = this.dateOfBirth;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "dateOfBirth", oldValue, dateOfBirth);
-        }
-        
         this.dateOfBirth = dateOfBirth;
     }
 
@@ -51,17 +50,13 @@ public abstract class _Artist extends PersistentObject {
 
         return name;
     }
+
     public void setName(String name) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "name", false);
+            objectContext.propertyChanged(this, "name", this.name, name);
         }
 
-        Object oldValue = this.name;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "name", oldValue, name);
-        }
-        
         this.name = name;
     }
 
@@ -69,25 +64,27 @@ public abstract class _Artist extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         return paintings;
     }
+
     public void addToPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.add(object);
     }
+
     public void removeFromPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.remove(object);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java b/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
index 7c59c64..57ccb07 100644
--- a/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
+++ b/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
@@ -3,7 +3,9 @@ package org.apache.cayenne.tutorial.persistent.client.auto;
 import java.util.List;
 
 import org.apache.cayenne.PersistentObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.client.Painting;
 import org.apache.cayenne.util.PersistentObjectList;
 
@@ -14,8 +16,8 @@ import org.apache.cayenne.util.PersistentObjectList;
  */
 public abstract class _Gallery extends PersistentObject {
 
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<List<Painting>> PAINTINGS = Property.create("paintings", List.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final ListProperty<Painting> PAINTINGS = PropertyFactory.createList("paintings", Painting.class);
 
     protected String name;
     protected List<Painting> paintings;
@@ -27,17 +29,13 @@ public abstract class _Gallery extends PersistentObject {
 
         return name;
     }
+
     public void setName(String name) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "name", false);
+            objectContext.propertyChanged(this, "name", this.name, name);
         }
 
-        Object oldValue = this.name;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "name", oldValue, name);
-        }
-        
         this.name = name;
     }
 
@@ -45,25 +43,27 @@ public abstract class _Gallery extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         return paintings;
     }
+
     public void addToPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.add(object);
     }
+
     public void removeFromPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.remove(object);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java b/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
index ab004f9..d6a4db2 100644
--- a/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
+++ b/tutorials/tutorial-rop-client-http2/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
@@ -2,7 +2,9 @@ package org.apache.cayenne.tutorial.persistent.client.auto;
 
 import org.apache.cayenne.PersistentObject;
 import org.apache.cayenne.ValueHolder;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.EntityProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.client.Artist;
 import org.apache.cayenne.tutorial.persistent.client.Gallery;
 import org.apache.cayenne.util.PersistentObjectHolder;
@@ -14,13 +16,13 @@ import org.apache.cayenne.util.PersistentObjectHolder;
  */
 public abstract class _Painting extends PersistentObject {
 
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<Artist> ARTIST = Property.create("artist", Artist.class);
-    public static final Property<Gallery> GALLERY = Property.create("gallery", Gallery.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final EntityProperty<org.apache.cayenne.tutorial.persistent.client.Artist> ARTIST = PropertyFactory.createEntity("artist", org.apache.cayenne.tutorial.persistent.client.Artist.class);
+    public static final EntityProperty<org.apache.cayenne.tutorial.persistent.client.Gallery> GALLERY = PropertyFactory.createEntity("gallery", org.apache.cayenne.tutorial.persistent.client.Gallery.class);
 
     protected String name;
-    protected ValueHolder artist;
-    protected ValueHolder gallery;
+    protected ValueHolder<Artist> artist;
+    protected ValueHolder<Gallery> gallery;
 
     public String getName() {
         if(objectContext != null) {
@@ -29,17 +31,13 @@ public abstract class _Painting extends PersistentObject {
 
         return name;
     }
+
     public void setName(String name) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "name", false);
+            objectContext.propertyChanged(this, "name", this.name, name);
         }
 
-        Object oldValue = this.name;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "name", oldValue, name);
-        }
-        
         this.name = name;
     }
 
@@ -47,25 +45,20 @@ public abstract class _Painting extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "artist", true);
         } else if (this.artist == null) {
-        	this.artist = new PersistentObjectHolder(this, "artist");
+        	this.artist = new PersistentObjectHolder<>(this, "artist");
 		}
 
-        return (Artist) artist.getValue();
+        return artist.getValue();
     }
+
     public void setArtist(Artist artist) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "artist", true);
+            objectContext.propertyChanged(this, "artist", this.artist.getValueDirectly(), artist);
         } else if (this.artist == null) {
-        	this.artist = new PersistentObjectHolder(this, "artist");
+        	this.artist = new PersistentObjectHolder<>(this, "artist");
 		}
 
-        // note how we notify ObjectContext of change BEFORE the object is actually
-        // changed... this is needed to take a valid current snapshot
-        Object oldValue = this.artist.getValueDirectly();
-        if (objectContext != null) {
-        	objectContext.propertyChanged(this, "artist", oldValue, artist);
-        }
-        
         this.artist.setValue(artist);
     }
 
@@ -73,25 +66,20 @@ public abstract class _Painting extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "gallery", true);
         } else if (this.gallery == null) {
-        	this.gallery = new PersistentObjectHolder(this, "gallery");
+        	this.gallery = new PersistentObjectHolder<>(this, "gallery");
 		}
 
-        return (Gallery) gallery.getValue();
+        return gallery.getValue();
     }
+
     public void setGallery(Gallery gallery) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "gallery", true);
+            objectContext.propertyChanged(this, "gallery", this.gallery.getValueDirectly(), gallery);
         } else if (this.gallery == null) {
-        	this.gallery = new PersistentObjectHolder(this, "gallery");
+        	this.gallery = new PersistentObjectHolder<>(this, "gallery");
 		}
 
-        // note how we notify ObjectContext of change BEFORE the object is actually
-        // changed... this is needed to take a valid current snapshot
-        Object oldValue = this.gallery.getValueDirectly();
-        if (objectContext != null) {
-        	objectContext.propertyChanged(this, "gallery", oldValue, gallery);
-        }
-        
         this.gallery.setValue(gallery);
     }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java b/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
index a558c2b..052709b 100644
--- a/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
+++ b/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Artist.java
@@ -1,13 +1,16 @@
 package org.apache.cayenne.tutorial.persistent.client.auto;
 
+import java.time.LocalDate;
+import java.util.List;
+
 import org.apache.cayenne.PersistentObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.DateProperty;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.client.Painting;
 import org.apache.cayenne.util.PersistentObjectList;
 
-import java.time.LocalDate;
-import java.util.List;
-
 /**
  * A generated persistent class mapped as "Artist" Cayenne entity. It is a good idea to
  * avoid changing this class manually, since it will be overwritten next time code is
@@ -15,9 +18,9 @@ import java.util.List;
  */
 public abstract class _Artist extends PersistentObject {
 
-    public static final Property<LocalDate> DATE_OF_BIRTH = Property.create("dateOfBirth", LocalDate.class);
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<List<Painting>> PAINTINGS = Property.create("paintings", List.class);
+    public static final DateProperty<LocalDate> DATE_OF_BIRTH = PropertyFactory.createDate("dateOfBirth", LocalDate.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final ListProperty<Painting> PAINTINGS = PropertyFactory.createList("paintings", Painting.class);
 
     protected LocalDate dateOfBirth;
     protected String name;
@@ -30,17 +33,13 @@ public abstract class _Artist extends PersistentObject {
 
         return dateOfBirth;
     }
+
     public void setDateOfBirth(LocalDate dateOfBirth) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "dateOfBirth", false);
+            objectContext.propertyChanged(this, "dateOfBirth", this.dateOfBirth, dateOfBirth);
         }
 
-        Object oldValue = this.dateOfBirth;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "dateOfBirth", oldValue, dateOfBirth);
-        }
-        
         this.dateOfBirth = dateOfBirth;
     }
 
@@ -51,17 +50,13 @@ public abstract class _Artist extends PersistentObject {
 
         return name;
     }
+
     public void setName(String name) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "name", false);
+            objectContext.propertyChanged(this, "name", this.name, name);
         }
 
-        Object oldValue = this.name;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "name", oldValue, name);
-        }
-        
         this.name = name;
     }
 
@@ -69,25 +64,27 @@ public abstract class _Artist extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         return paintings;
     }
+
     public void addToPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.add(object);
     }
+
     public void removeFromPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.remove(object);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java b/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
index 7c59c64..57ccb07 100644
--- a/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
+++ b/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Gallery.java
@@ -3,7 +3,9 @@ package org.apache.cayenne.tutorial.persistent.client.auto;
 import java.util.List;
 
 import org.apache.cayenne.PersistentObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.client.Painting;
 import org.apache.cayenne.util.PersistentObjectList;
 
@@ -14,8 +16,8 @@ import org.apache.cayenne.util.PersistentObjectList;
  */
 public abstract class _Gallery extends PersistentObject {
 
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<List<Painting>> PAINTINGS = Property.create("paintings", List.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final ListProperty<Painting> PAINTINGS = PropertyFactory.createList("paintings", Painting.class);
 
     protected String name;
     protected List<Painting> paintings;
@@ -27,17 +29,13 @@ public abstract class _Gallery extends PersistentObject {
 
         return name;
     }
+
     public void setName(String name) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "name", false);
+            objectContext.propertyChanged(this, "name", this.name, name);
         }
 
-        Object oldValue = this.name;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "name", oldValue, name);
-        }
-        
         this.name = name;
     }
 
@@ -45,25 +43,27 @@ public abstract class _Gallery extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         return paintings;
     }
+
     public void addToPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.add(object);
     }
+
     public void removeFromPaintings(Painting object) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "paintings", true);
         } else if (this.paintings == null) {
-        	this.paintings = new PersistentObjectList(this, "paintings");
+        	this.paintings = new PersistentObjectList<>(this, "paintings");
 		}
 
         this.paintings.remove(object);

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java b/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
index ab004f9..d6a4db2 100644
--- a/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
+++ b/tutorials/tutorial-rop-client/src/main/java/org/apache/cayenne/tutorial/persistent/client/auto/_Painting.java
@@ -2,7 +2,9 @@ package org.apache.cayenne.tutorial.persistent.client.auto;
 
 import org.apache.cayenne.PersistentObject;
 import org.apache.cayenne.ValueHolder;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.exp.property.EntityProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.client.Artist;
 import org.apache.cayenne.tutorial.persistent.client.Gallery;
 import org.apache.cayenne.util.PersistentObjectHolder;
@@ -14,13 +16,13 @@ import org.apache.cayenne.util.PersistentObjectHolder;
  */
 public abstract class _Painting extends PersistentObject {
 
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<Artist> ARTIST = Property.create("artist", Artist.class);
-    public static final Property<Gallery> GALLERY = Property.create("gallery", Gallery.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final EntityProperty<org.apache.cayenne.tutorial.persistent.client.Artist> ARTIST = PropertyFactory.createEntity("artist", org.apache.cayenne.tutorial.persistent.client.Artist.class);
+    public static final EntityProperty<org.apache.cayenne.tutorial.persistent.client.Gallery> GALLERY = PropertyFactory.createEntity("gallery", org.apache.cayenne.tutorial.persistent.client.Gallery.class);
 
     protected String name;
-    protected ValueHolder artist;
-    protected ValueHolder gallery;
+    protected ValueHolder<Artist> artist;
+    protected ValueHolder<Gallery> gallery;
 
     public String getName() {
         if(objectContext != null) {
@@ -29,17 +31,13 @@ public abstract class _Painting extends PersistentObject {
 
         return name;
     }
+
     public void setName(String name) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "name", false);
+            objectContext.propertyChanged(this, "name", this.name, name);
         }
 
-        Object oldValue = this.name;
-        // notify objectContext about simple property change
-        if(objectContext != null) {
-            objectContext.propertyChanged(this, "name", oldValue, name);
-        }
-        
         this.name = name;
     }
 
@@ -47,25 +45,20 @@ public abstract class _Painting extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "artist", true);
         } else if (this.artist == null) {
-        	this.artist = new PersistentObjectHolder(this, "artist");
+        	this.artist = new PersistentObjectHolder<>(this, "artist");
 		}
 
-        return (Artist) artist.getValue();
+        return artist.getValue();
     }
+
     public void setArtist(Artist artist) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "artist", true);
+            objectContext.propertyChanged(this, "artist", this.artist.getValueDirectly(), artist);
         } else if (this.artist == null) {
-        	this.artist = new PersistentObjectHolder(this, "artist");
+        	this.artist = new PersistentObjectHolder<>(this, "artist");
 		}
 
-        // note how we notify ObjectContext of change BEFORE the object is actually
-        // changed... this is needed to take a valid current snapshot
-        Object oldValue = this.artist.getValueDirectly();
-        if (objectContext != null) {
-        	objectContext.propertyChanged(this, "artist", oldValue, artist);
-        }
-        
         this.artist.setValue(artist);
     }
 
@@ -73,25 +66,20 @@ public abstract class _Painting extends PersistentObject {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "gallery", true);
         } else if (this.gallery == null) {
-        	this.gallery = new PersistentObjectHolder(this, "gallery");
+        	this.gallery = new PersistentObjectHolder<>(this, "gallery");
 		}
 
-        return (Gallery) gallery.getValue();
+        return gallery.getValue();
     }
+
     public void setGallery(Gallery gallery) {
         if(objectContext != null) {
             objectContext.prepareForAccess(this, "gallery", true);
+            objectContext.propertyChanged(this, "gallery", this.gallery.getValueDirectly(), gallery);
         } else if (this.gallery == null) {
-        	this.gallery = new PersistentObjectHolder(this, "gallery");
+        	this.gallery = new PersistentObjectHolder<>(this, "gallery");
 		}
 
-        // note how we notify ObjectContext of change BEFORE the object is actually
-        // changed... this is needed to take a valid current snapshot
-        Object oldValue = this.gallery.getValueDirectly();
-        if (objectContext != null) {
-        	objectContext.propertyChanged(this, "gallery", oldValue, gallery);
-        }
-        
         this.gallery.setValue(gallery);
     }
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/63a32d82/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Artist.java
----------------------------------------------------------------------
diff --git a/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Artist.java b/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Artist.java
index 147f9f7..5ff7823 100644
--- a/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Artist.java
+++ b/tutorials/tutorial-rop-server-http2/src/main/java/org/apache/cayenne/tutorial/persistent/auto/_Artist.java
@@ -1,10 +1,16 @@
 package org.apache.cayenne.tutorial.persistent.auto;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.time.LocalDate;
 import java.util.List;
 
-import org.apache.cayenne.CayenneDataObject;
-import org.apache.cayenne.exp.Property;
+import org.apache.cayenne.BaseDataObject;
+import org.apache.cayenne.exp.property.DateProperty;
+import org.apache.cayenne.exp.property.ListProperty;
+import org.apache.cayenne.exp.property.PropertyFactory;
+import org.apache.cayenne.exp.property.StringProperty;
 import org.apache.cayenne.tutorial.persistent.Painting;
 
 /**
@@ -13,40 +19,115 @@ import org.apache.cayenne.tutorial.persistent.Painting;
  * since it may be overwritten next time code is regenerated.
  * If you need to make any customizations, please use subclass.
  */
-public abstract class _Artist extends CayenneDataObject {
+public abstract class _Artist extends BaseDataObject {
 
     private static final long serialVersionUID = 1L; 
 
     public static final String ID_PK_COLUMN = "ID";
 
-    public static final Property<LocalDate> DATE_OF_BIRTH = Property.create("dateOfBirth", LocalDate.class);
-    public static final Property<String> NAME = Property.create("name", String.class);
-    public static final Property<List<Painting>> PAINTINGS = Property.create("paintings", List.class);
+    public static final DateProperty<LocalDate> DATE_OF_BIRTH = PropertyFactory.createDate("dateOfBirth", LocalDate.class);
+    public static final StringProperty<String> NAME = PropertyFactory.createString("name", String.class);
+    public static final ListProperty<Painting> PAINTINGS = PropertyFactory.createList("paintings", Painting.class);
+
+    protected LocalDate dateOfBirth;
+    protected String name;
+
+    protected Object paintings;
 
     public void setDateOfBirth(LocalDate dateOfBirth) {
-        writeProperty("dateOfBirth", dateOfBirth);
+        beforePropertyWrite("dateOfBirth", this.dateOfBirth, dateOfBirth);
+        this.dateOfBirth = dateOfBirth;
     }
+
     public LocalDate getDateOfBirth() {
-        return (LocalDate)readProperty("dateOfBirth");
+        beforePropertyRead("dateOfBirth");
+        return this.dateOfBirth;
     }
 
     public void setName(String name) {
-        writeProperty("name", name);
+        beforePropertyWrite("name", this.name, name);
+        this.name = name;
     }
+
     public String getName() {
-        return (String)readProperty("name");
+        beforePropertyRead("name");
+        return this.name;
     }
 
     public void addToPaintings(Painting obj) {
         addToManyTarget("paintings", obj, true);
     }
+
     public void removeFromPaintings(Painting obj) {
         removeToManyTarget("paintings", obj, true);
     }
+
     @SuppressWarnings("unchecked")
     public List<Painting> getPaintings() {
         return (List<Painting>)readProperty("paintings");
     }
 
+    @Override
+    public Object readPropertyDirectly(String propName) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch(propName) {
+            case "dateOfBirth":
+                return this.dateOfBirth;
+            case "name":
+                return this.name;
+            case "paintings":
+                return this.paintings;
+            default:
+                return super.readPropertyDirectly(propName);
+        }
+    }
+
+    @Override
+    public void writePropertyDirectly(String propName, Object val) {
+        if(propName == null) {
+            throw new IllegalArgumentException();
+        }
+
+        switch (propName) {
+            case "dateOfBirth":
+                this.dateOfBirth = (LocalDate)val;
+                break;
+            case "name":
+                this.name = (String)val;
+                break;
+            case "paintings":
+                this.paintings = val;
+                break;
+            default:
+                super.writePropertyDirectly(propName, val);
+        }
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        writeSerialized(out);
+    }
+
+    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        readSerialized(in);
+    }
+
+    @Override
+    protected void writeState(ObjectOutputStream out) throws IOException {
+        super.writeState(out);
+        out.writeObject(this.dateOfBirth);
+        out.writeObject(this.name);
+        out.writeObject(this.paintings);
+    }
+
+    @Override
+    protected void readState(ObjectInputStream in) throws IOException, ClassNotFoundException {
+        super.readState(in);
+        this.dateOfBirth = (LocalDate)in.readObject();
+        this.name = (String)in.readObject();
+        this.paintings = in.readObject();
+    }
 
 }