You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@polygene.apache.org by ni...@apache.org on 2017/10/26 07:34:41 UTC

[11/33] polygene-java git commit: A lot of things fixed to get closer to a working implementation.

A lot of things fixed to get closer to a working implementation.

Signed-off-by: niclas <ni...@hedhman.org>


Project: http://git-wip-us.apache.org/repos/asf/polygene-java/repo
Commit: http://git-wip-us.apache.org/repos/asf/polygene-java/commit/59a08629
Tree: http://git-wip-us.apache.org/repos/asf/polygene-java/tree/59a08629
Diff: http://git-wip-us.apache.org/repos/asf/polygene-java/diff/59a08629

Branch: refs/heads/develop
Commit: 59a08629239a38bdf93cf02fb1a3722e36abbdd8
Parents: ffd7207
Author: niclas <ni...@hedhman.org>
Authored: Sun Jun 11 11:43:12 2017 +0800
Committer: niclas <ni...@hedhman.org>
Committed: Sun Jun 11 11:43:12 2017 +0800

----------------------------------------------------------------------
 .../test/entity/AbstractEntityStoreTest.java    |   3 -
 extensions/entitystore-jooq/dev-status.xml      |  20 +-
 .../entitystore-jooq/src/docs/es-jooq.txt       |  58 +++++
 extensions/entitystore-jooq/src/docs/es-orm.txt |  58 -----
 .../entitystore/jooq/AssociationValue.java      |   7 +-
 .../polygene/entitystore/jooq/BaseEntity.java   |   3 +-
 .../entitystore/jooq/EntitiesTable.java         | 210 ++++++++++++++-----
 .../entitystore/jooq/JooqEntityStoreMixin.java  | 128 ++++++-----
 .../polygene/entitystore/jooq/MixinTable.java   | 197 +++++++++++------
 .../polygene/entitystore/jooq/SqlTable.java     |  37 +++-
 .../polygene/entitystore/jooq/TableFields.java  |  22 +-
 .../polygene/entitystore/jooq/TypesTable.java   |  10 +-
 .../entitystore/jooq/JooqEntityStoreTest.java   |  21 +-
 manual/src/docs/userguide/extensions.txt        |   4 +
 14 files changed, 506 insertions(+), 272 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/core/testsupport/src/main/java/org/apache/polygene/test/entity/AbstractEntityStoreTest.java
----------------------------------------------------------------------
diff --git a/core/testsupport/src/main/java/org/apache/polygene/test/entity/AbstractEntityStoreTest.java b/core/testsupport/src/main/java/org/apache/polygene/test/entity/AbstractEntityStoreTest.java
index 2bb6abb..0eee83a 100644
--- a/core/testsupport/src/main/java/org/apache/polygene/test/entity/AbstractEntityStoreTest.java
+++ b/core/testsupport/src/main/java/org/apache/polygene/test/entity/AbstractEntityStoreTest.java
@@ -359,7 +359,6 @@ public abstract class AbstractEntityStoreTest
         try( UnitOfWork unitOfWork = unitOfWorkFactory.newUnitOfWork() )
         {
             EntityBuilder<TestEntity> builder = unitOfWork.newEntityBuilder( TestEntity.class );
-
             testEntity = builder.newInstance();
             unitOfWork.complete();
         }
@@ -368,7 +367,6 @@ public abstract class AbstractEntityStoreTest
             testEntity = unitOfWork.get( testEntity );
             testEntity.name().set( "Rickard" );
             version = spi.entityStateOf( testEntity ).version();
-
             unitOfWork.complete();
         }
         try( UnitOfWork unitOfWork = unitOfWorkFactory.newUnitOfWork() )
@@ -376,7 +374,6 @@ public abstract class AbstractEntityStoreTest
             testEntity = unitOfWork.get( testEntity );
             String newVersion = spi.entityStateOf( testEntity ).version();
             assertThat( "version has not changed", newVersion, not( equalTo( version ) ) );
-
             unitOfWork.complete();
         }
     }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/dev-status.xml
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/dev-status.xml b/extensions/entitystore-jooq/dev-status.xml
index 0914c52..6710bdd 100644
--- a/extensions/entitystore-jooq/dev-status.xml
+++ b/extensions/entitystore-jooq/dev-status.xml
@@ -23,16 +23,16 @@
         xsi:schemaLocation="http://polygene.apache.org/schemas/2008/dev-status/1
         http://polygene.apache.org/schemas/2008/dev-status/1/dev-status.xsd">
   <status>
-    <!--none,early,beta,stable,mature-->
-    <codebase>stable</codebase>
+        <!--none,early,beta,stable,mature-->
+        <codebase>early</codebase>
 
-    <!-- none, brief, good, complete -->
-    <documentation>good</documentation>
+        <!-- none, brief, good, complete -->
+        <documentation>none</documentation>
 
-    <!-- none, some, good, complete -->
-    <unittests>good</unittests>
-  </status>
-  <licenses>
-    <license>ALv2</license>
-  </licenses>
+        <!-- none, some, good, complete -->
+        <unittests>good</unittests>
+    </status>
+    <licenses>
+        <license>ALv2</license>
+    </licenses>
 </module>

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/src/docs/es-jooq.txt
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/docs/es-jooq.txt b/extensions/entitystore-jooq/src/docs/es-jooq.txt
new file mode 100644
index 0000000..a36d463
--- /dev/null
+++ b/extensions/entitystore-jooq/src/docs/es-jooq.txt
@@ -0,0 +1,58 @@
+///////////////////////////////////////////////////////////////
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+///////////////////////////////////////////////////////////////
+
+[[extension-es-jooq,SQL EntityStore]]
+= ORM EntityStore =
+
+[devstatus]
+--------------
+source=extensions/entitystore-jooq/dev-status.xml
+--------------
+
+This entitystore is backed by a SQL server, and maps each mixin type of the Composite into separate tables. This is more
+enterprise-friendly, but comes at the cost of less performance compared to the <<extension-es-sql>>.
+
+This extension fully leverage the <<library-sql>> meaning that you must use it to assemble your DataSource and that you
+get <<library-circuitbreaker,Circuit Breaker>> and <<library-jmx, JMX>> integration for free.
+
+include::../../build/docs/buildinfo/artifact.txt[]
+
+== Assembly ==
+
+Assembly is done using the provided Assembler:
+
+[snippet,java]
+----
+source=extensions/entitystore-jooq/src/test/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreTest.java
+tag=assembly
+----
+
+== Configuration ==
+
+Here are the available configuration properties:
+
+[snippet,java]
+----
+source=extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreConfiguration.java
+tag=config
+----
+
+All authentication related properties are optional.
+By default no authentication is used.
+As soon as you provide a `username`, authentication is set up.

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/src/docs/es-orm.txt
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/docs/es-orm.txt b/extensions/entitystore-jooq/src/docs/es-orm.txt
deleted file mode 100644
index 413eb7b..0000000
--- a/extensions/entitystore-jooq/src/docs/es-orm.txt
+++ /dev/null
@@ -1,58 +0,0 @@
-///////////////////////////////////////////////////////////////
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
-///////////////////////////////////////////////////////////////
-
-[[extension-es-orm,ORM EntityStore]]
-= ORM EntityStore =
-
-[devstatus]
---------------
-source=extensions/entitystore-orm/dev-status.xml
---------------
-
-This entitystore is backed by a SQL server, and maps each type of the Composite into separate tables. This is more
-enterprise-friendly, but comes at the cost of less performance compared to the <<extension-es-sql>>.
-
-This extension fully leverage the <<library-sql>> meaning that you must use it to assemble your DataSource and that you
-get <<library-circuitbreaker,Circuit Breaker>> and <<library-jmx, JMX>> integration for free.
-
-include::../../build/docs/buildinfo/artifact.txt[]
-
-== Assembly ==
-
-Assembly is done using the provided Assembler:
-
-[snippet,java]
-----
-source=extensions/entitystore-riak/src/test/java/org/apache/polygene/entitystore/orm/OrmEntityStoreTest.java
-tag=assembly
-----
-
-== Configuration ==
-
-Here are the available configuration properties:
-
-[snippet,java]
-----
-source=extensions/entitystore-riak/src/main/java/org/apache/polygene/entitystore/orm/OrmEntityStoreConfiguration.java
-tag=config
-----
-
-All authentication related properties are optional.
-By default no authentication is used.
-As soon as you provide a `username`, authentication is set up.

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/AssociationValue.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/AssociationValue.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/AssociationValue.java
index 81331cf..528ab8b 100644
--- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/AssociationValue.java
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/AssociationValue.java
@@ -17,9 +17,12 @@
  */
 package org.apache.polygene.entitystore.jooq;
 
-class AssociationValue
+import org.apache.polygene.api.common.QualifiedName;
+
+@SuppressWarnings( "WeakerAccess" )
+public class AssociationValue
 {
-    String name;
+    QualifiedName name;
     String position;
     String reference;
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/BaseEntity.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/BaseEntity.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/BaseEntity.java
index e4eaa40..3c16f16 100644
--- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/BaseEntity.java
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/BaseEntity.java
@@ -21,7 +21,8 @@ import java.time.Instant;
 import org.apache.polygene.api.entity.EntityDescriptor;
 import org.apache.polygene.api.identity.Identity;
 
-class BaseEntity
+@SuppressWarnings( "WeakerAccess" )
+public class BaseEntity
 {
     EntityDescriptor type;
     Identity identity;

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/EntitiesTable.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/EntitiesTable.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/EntitiesTable.java
index dc765a9..001b590 100644
--- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/EntitiesTable.java
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/EntitiesTable.java
@@ -26,12 +26,18 @@ import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import org.apache.polygene.api.association.AssociationDescriptor;
 import org.apache.polygene.api.common.QualifiedName;
+import org.apache.polygene.api.composite.Composite;
+import org.apache.polygene.api.entity.EntityComposite;
 import org.apache.polygene.api.entity.EntityDescriptor;
 import org.apache.polygene.api.entity.EntityReference;
+import org.apache.polygene.api.identity.HasIdentity;
+import org.apache.polygene.api.identity.StringIdentity;
 import org.apache.polygene.api.property.PropertyDescriptor;
 import org.apache.polygene.api.structure.ModuleDescriptor;
 import org.apache.polygene.api.type.EntityCompositeType;
@@ -48,10 +54,14 @@ import org.jooq.Schema;
 import org.jooq.SelectJoinStep;
 import org.jooq.SelectQuery;
 import org.jooq.Table;
+import org.jooq.impl.DSL;
 
+@SuppressWarnings( "WeakerAccess" )
 public class EntitiesTable
     implements TableFields
 {
+    private static final Predicate<? super Class<?>> NOT_COMPOSITE = type -> !( type.equals( Composite.class ) || type.equals( EntityComposite.class ) );
+    private static final Predicate<? super Class<?>> NOT_HASIDENTITY = type -> !( type.equals( HasIdentity.class ) );
     private Map<EntityCompositeType, Set<Class<?>>> mixinTypeCache = new ConcurrentHashMap<>();
     private Map<Class<?>, MixinTable> mixinTablesCache = new ConcurrentHashMap<>();
 
@@ -60,6 +70,7 @@ public class EntitiesTable
     private final TypesTable types;
     private final Schema schema;
     private String applicationVersion;
+    private boolean replacementStrategy = false;  // Figure out later if we should support both and if so, how.
 
     EntitiesTable( JooqDslContext dsl, Schema schema, TypesTable types, String applicationVersion, String entitiesTableName )
     {
@@ -72,7 +83,6 @@ public class EntitiesTable
 
     public BaseEntity fetchEntity( EntityReference reference, ModuleDescriptor module )
     {
-        BaseEntity result = new BaseEntity();
 
         Result<Record> baseEntityResult = dsl
             .selectFrom( entitiesTable )
@@ -83,18 +93,32 @@ public class EntitiesTable
         {
             throw new EntityNotFoundException( reference );
         }
-        Record baseEntity = baseEntityResult.get( 0 );
-        String typeName = baseEntity.field( typeNameColumn ).get( baseEntity );
+        Record row = baseEntityResult.get( 0 );
+        return toBaseEntity( row, module );
+    }
+
+    protected BaseEntity toBaseEntity( Record row, ModuleDescriptor module )
+    {
+        BaseEntity result = new BaseEntity();
+        String typeName = row.field( typeNameColumn ).get( row );
         result.type = findEntityDescriptor( typeName, module );
-        result.version = baseEntity.field( versionColumn ).get( baseEntity );
-        result.applicationVersion = baseEntity.field( applicationVersionColumn ).get( baseEntity );
-        result.identity = EntityReference.parseEntityReference( baseEntity.field( identityColumn ).get( baseEntity ) ).identity();
-        result.currentValueIdentity = EntityReference.parseEntityReference( baseEntity.field( valueIdentityColumn ).get( baseEntity ) ).identity();
-        result.modifedAt = Instant.ofEpochMilli( baseEntity.field( modifiedColumn ).get( baseEntity ).getTime() );
-        result.createdAt = Instant.ofEpochMilli( baseEntity.field( createdColumn ).get( baseEntity ).getTime() );
+        result.version = row.field( versionColumn ).get( row );
+        result.applicationVersion = row.field( applicationVersionColumn ).get( row );
+        result.identity = new StringIdentity( row.field( identityColumn ).get( row ) );
+        result.currentValueIdentity = EntityReference.parseEntityReference( row.field( valueIdentityColumn ).get( row ) ).identity();
+        result.modifedAt = Instant.ofEpochMilli( row.field( modifiedColumn ).get( row ).getTime() );
+        result.createdAt = Instant.ofEpochMilli( row.field( createdColumn ).get( row ).getTime() );
         return result;
     }
 
+    public Stream<BaseEntity> fetchAll( EntityDescriptor type, ModuleDescriptor module )
+    {
+        Result<Record> baseEntityResult = dsl
+            .selectFrom( entitiesTable )
+            .fetch();
+        return baseEntityResult.stream().map( record -> toBaseEntity( record, module ) );
+    }
+
     private EntityDescriptor findEntityDescriptor( String typeName, ModuleDescriptor module )
     {
         try
@@ -108,34 +132,36 @@ public class EntitiesTable
         }
     }
 
-    void insertEntity( DefaultEntityState state )
+    void insertEntity( DefaultEntityState state, BaseEntity baseEntity )
     {
         EntityCompositeType compositeType = state.entityDescriptor().valueType();
-        Set<Class<?>> mixinTypes = mixinTypeCache.computeIfAbsent( compositeType, type ->
-        {
-            Set<Class<?>> mixins = compositeType
-                .properties()
-                .map( PropertyDescriptor::accessor )
-                .filter( Classes.instanceOf( Method.class ) )
-                .map( accessor -> (Method) accessor )
-                .map( Method::getDeclaringClass )
-                .collect( Collectors.toSet() );
-            Set<Class<?>> mixinsWithAssociations = mixinsOf( compositeType.associations() );
-            Set<Class<?>> mixinsWithManyAssociations = mixinsOf( compositeType.manyAssociations() );
-            Set<Class<?>> mixinsWithNamedAssociations = mixinsOf( compositeType.namedAssociations() );
-            mixins.addAll( mixinsWithAssociations );
-            mixins.addAll( mixinsWithManyAssociations );
-            mixins.addAll( mixinsWithNamedAssociations );
-            return mixins;
-        } );
-        String valueIdentity = UUID.randomUUID().toString();
+        Set<Class<?>> mixinTypes = mixinTypeCache.computeIfAbsent( compositeType, createMixinTypesSet( compositeType ) );
         mixinTypes.forEach( type ->
                             {
                                 MixinTable table = findMixinTable( type, state.entityDescriptor() );
-                                table.insertMixinState( state, valueIdentity );
+                                table.insertMixinState( state, baseEntity.currentValueIdentity.toString() );
                             } );
     }
 
+    void modifyEntity( DefaultEntityState state, BaseEntity baseEntity, EntityStoreUnitOfWork uow )
+    {
+        updateBaseEntity( baseEntity, uow );
+        if( replacementStrategy )
+        {
+            insertEntity( state, baseEntity );      // replacement strategy (more safe)
+        }
+        else
+        {
+            EntityCompositeType compositeType = state.entityDescriptor().valueType();
+            Set<Class<?>> mixinTypes = mixinTypeCache.computeIfAbsent( compositeType, createMixinTypesSet( compositeType ) );
+            mixinTypes.forEach( type ->
+                                {
+                                    MixinTable table = findMixinTable( type, state.entityDescriptor() );
+                                    table.modifyMixinState( state, baseEntity.currentValueIdentity.toString() );
+                                } );
+        }
+    }
+
     private MixinTable findMixinTable( Class<?> type, EntityDescriptor entityDescriptor )
     {
         return mixinTablesCache.computeIfAbsent( type, t -> new MixinTable( dsl, schema, types, type, entityDescriptor ) );
@@ -148,17 +174,32 @@ public class EntitiesTable
             .filter( Classes.instanceOf( Method.class ) )
             .map( accessor -> (Method) accessor )
             .map( Method::getDeclaringClass )
+            .filter( NOT_HASIDENTITY )
+            .filter( NOT_COMPOSITE )
             .collect( Collectors.toSet() );
     }
 
-    private String columnNameOf( QualifiedName propertyName )
-    {
-        return null;
-    }
-
-    void modifyEntity( Class<?> mixinType, DefaultEntityState state )
+    private Function<EntityCompositeType, Set<Class<?>>> createMixinTypesSet( EntityCompositeType compositeType )
     {
-
+        return type ->
+        {
+            Set<Class<?>> mixins = compositeType
+                .properties()
+                .map( PropertyDescriptor::accessor )
+                .filter( Classes.instanceOf( Method.class ) )
+                .map( accessor -> (Method) accessor )
+                .map( Method::getDeclaringClass )
+                .filter( NOT_HASIDENTITY )
+                .filter( NOT_COMPOSITE )
+                .collect( Collectors.toSet() );
+            Set<Class<?>> mixinsWithAssociations = mixinsOf( compositeType.associations() );
+            Set<Class<?>> mixinsWithManyAssociations = mixinsOf( compositeType.manyAssociations() );
+            Set<Class<?>> mixinsWithNamedAssociations = mixinsOf( compositeType.namedAssociations() );
+            mixins.addAll( mixinsWithAssociations );
+            mixins.addAll( mixinsWithManyAssociations );
+            mixins.addAll( mixinsWithNamedAssociations );
+            return mixins;
+        };
     }
 
     void createNewBaseEntity( EntityReference reference, EntityDescriptor descriptor, EntityStoreUnitOfWork uow )
@@ -175,6 +216,27 @@ public class EntitiesTable
            .execute();
     }
 
+    private void updateBaseEntity( BaseEntity entity, EntityStoreUnitOfWork uow )
+    {
+        entity.version = increment( entity.version );
+        if( replacementStrategy )
+        {
+            entity.currentValueIdentity = new StringIdentity( UUID.randomUUID().toString() );
+        }
+        dsl.update( entitiesTable )
+           .set( modifiedColumn, new Timestamp( uow.currentTime().toEpochMilli() ) )
+           .set( valueIdentityColumn, entity.currentValueIdentity.toString() )
+           .set( versionColumn, entity.version )
+           .set( applicationVersionColumn, applicationVersion )
+           .execute();
+    }
+
+    private String increment( String version )
+    {
+        long ver = Long.parseLong( version );
+        return Long.toString( ver + 1 );
+    }
+
     /**
      * Builds the SELECT statement for a given entity.
      * <p>
@@ -217,31 +279,85 @@ public class EntitiesTable
      */
     public SelectQuery<Record> createGetEntityQuery( EntityDescriptor entityDescriptor, EntityReference reference )
     {
+        List<Table<Record>> joins = getMixinTables( entityDescriptor );
         SelectJoinStep<Record> from = dsl.select().from( entitiesTable );
-        List<Table<Record>> joins = getTableJoins( entityDescriptor );
         for( Table<Record> joinedTable : joins )
         {
-            Field<String> joinedField = joinedTable.field( identityColumn );
-            Condition joinCondition = joinedField.eq( entitiesTable.field( valueIdentityColumn ) );
+            Condition joinCondition = valueIdentityColumn.eq( identityColumnOf( joinedTable ) );
+            from = from.leftJoin( joinedTable ).on( joinCondition );
+        }
+        return from.where( identityColumnOf( entitiesTable ).eq( reference.identity().toString() ) ).getQuery();
+    }
+
+    public void fetchAssociations( BaseEntity entity, EntityDescriptor entityDescriptor, Consumer<AssociationValue> consume )
+    {
+        List<Table<Record>> joins = getAssocationsTables( entityDescriptor );
+        SelectJoinStep<Record> from = dsl.select().from( entitiesTable );
+        for( Table<Record> joinedTable : joins )
+        {
+            Condition joinCondition = valueIdentityColumn.eq( identityColumnOf( joinedTable ) );
             from = from.join( joinedTable ).on( joinCondition );
         }
-        return from.where( identityColumn.eq( reference.identity().toString() ) ).getQuery();
+        String reference = entity.identity.toString();
+        SelectQuery<Record> query = from.where( identityColumnOf( entitiesTable ).eq( reference ) ).getQuery();
+        Result<Record> result = query.fetch();
+        result.forEach( record ->
+                        {
+                            AssociationValue value = new AssociationValue();
+                            value.name = QualifiedName.fromClass( entityDescriptor.primaryType(), record.getValue( nameColumn ) );
+                            value.position = record.getValue( indexColumn );
+                            value.reference = record.getValue( referenceColumn );
+                            consume.accept( value );
+                        } );
     }
 
-    public void fetchAssociations( Record record, Consumer<AssociationValue> consume )
+    private Field<String> identityColumnOf( Table<Record> joinedTable )
     {
-        AssociationValue value = new AssociationValue();
-        value.name = record.getValue( nameColumn );
-        value.position = record.getValue( indexColumn );
-        value.reference = record.getValue( referenceColumn );
-        consume.accept( value );
+        return DSL.field( DSL.name( joinedTable.getName(), identityColumn.getName() ), String.class );
     }
 
-    public List<Table<Record>> getTableJoins( EntityDescriptor entityDescriptor )
+    public List<Table<Record>> getMixinTables( EntityDescriptor entityDescriptor )
     {
         return entityDescriptor
             .mixinTypes()
+            .filter( NOT_COMPOSITE )
+            .filter( NOT_HASIDENTITY )
             .map( ( Class<?> type ) -> types.tableFor( type, entityDescriptor ) )
             .collect( Collectors.toList() );
     }
+
+    public List<Table<Record>> getAssocationsTables( EntityDescriptor entityDescriptor )
+    {
+        return entityDescriptor
+            .mixinTypes()
+            .filter( NOT_COMPOSITE )
+            .filter( NOT_HASIDENTITY )
+            .map( type -> findMixinTable( type, entityDescriptor ) )
+            .map( MixinTable::associationsTable )
+            .collect( Collectors.toList() );
+    }
+
+    public void removeEntity( EntityReference entityReference, EntityDescriptor descriptor )
+    {
+        ModuleDescriptor module = descriptor.module();
+        BaseEntity baseEntity = fetchEntity( entityReference, module );
+        if( replacementStrategy )
+        {
+            // TODO;  Mark deleted, I guess... not implemented
+        }
+        else
+        {
+            dsl.delete( entitiesTable )
+               .where(
+                   identityColumnOf( entitiesTable ).eq( entityReference.identity().toString() )
+                     )
+               .execute()
+            ;
+            String valueId = baseEntity.currentValueIdentity.toString();
+            List<Table<Record>> mixinTables = getMixinTables( descriptor );
+            List<Table<Record>> assocTables = getAssocationsTables( descriptor );
+            mixinTables.forEach( table -> dsl.delete( table ).where( identityColumnOf( table ).eq( valueId ) ).execute() );
+            assocTables.forEach( table -> dsl.delete( table ).where( identityColumnOf( table ).eq( valueId ) ).execute() );
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreMixin.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreMixin.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreMixin.java
index a22354b..5a062d8 100644
--- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreMixin.java
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreMixin.java
@@ -28,9 +28,11 @@ import org.apache.polygene.api.association.AssociationStateDescriptor;
 import org.apache.polygene.api.common.QualifiedName;
 import org.apache.polygene.api.entity.EntityDescriptor;
 import org.apache.polygene.api.entity.EntityReference;
+import org.apache.polygene.api.identity.HasIdentity;
 import org.apache.polygene.api.identity.IdentityGenerator;
 import org.apache.polygene.api.injection.scope.Service;
 import org.apache.polygene.api.injection.scope.This;
+import org.apache.polygene.api.serialization.Serialization;
 import org.apache.polygene.api.structure.ModuleDescriptor;
 import org.apache.polygene.api.usecase.Usecase;
 import org.apache.polygene.spi.entity.EntityState;
@@ -57,6 +59,9 @@ public class JooqEntityStoreMixin
     @Service
     private IdentityGenerator identityGenerator;
 
+    @Service
+    private Serialization serialization;
+
     @Override
     public EntityState newEntityState( EntityStoreUnitOfWork unitOfWork, EntityReference reference, EntityDescriptor entityDescriptor )
     {
@@ -73,36 +78,45 @@ public class JooqEntityStoreMixin
         {
             throw new EntityNotFoundException( reference );
         }
+        return toEntityState( result, baseEntity, reference );
+    }
+
+    protected EntityState toEntityState( Result<Record> result, BaseEntity baseEntity, EntityReference reference )
+    {
         AssociationStateDescriptor stateDescriptor = baseEntity.type.state();
         Map<QualifiedName, Object> properties = new HashMap<>();
-        stateDescriptor.properties().forEach( prop ->
-                                              {
-                                                  QualifiedName qualifiedName = prop.qualifiedName();
-                                                  Object value = result.getValue( 0, qualifiedName.name() );
-                                                  properties.put( qualifiedName, value );
-                                              } );
+        stateDescriptor.properties()
+                       .filter( prop -> !HasIdentity.IDENTITY_STATE_NAME.equals( prop.qualifiedName() ) )
+                       .forEach( prop ->
+                                 {
+                                     QualifiedName qualifiedName = prop.qualifiedName();
+                                     Object value = result.getValue( 0, qualifiedName.name() );
+                                     properties.put( qualifiedName, value );
+                                 } );
         Map<QualifiedName, EntityReference> assocations = new HashMap<>();
-        stateDescriptor.associations().forEach( assoc ->
-                                                {
-                                                    QualifiedName qualifiedName = assoc.qualifiedName();
-                                                    String value = (String) result.getValue( 0, qualifiedName.name() );
-                                                    assocations.put( qualifiedName, parseEntityReference( value ) );
-                                                } );
+        stateDescriptor.associations()
+                       .forEach( assoc ->
+                                 {
+                                     QualifiedName qualifiedName = assoc.qualifiedName();
+                                     String value = (String) result.getValue( 0, qualifiedName.name() );
+                                     if( value != null )
+                                     {
+                                         assocations.put( qualifiedName, parseEntityReference( value ) );
+                                     }
+                                 } );
         Map<QualifiedName, List<EntityReference>> manyAssocs = new HashMap<>();
         Map<QualifiedName, Map<String, EntityReference>> namedAssocs = new HashMap<>();
-        result.forEach( record ->
-                            sqlTable.fetchAssociations( record, associationValue ->
-                            {
-                                // TODO: Perhaps introduce "preserveManyAssociationOrder" option which would have an additional column, separating 'ordinal position' and 'name position'
-                                if( associationValue.position == null )
-                                {
-                                    addManyAssociation( stateDescriptor, manyAssocs, associationValue );
-                                }
-                                else
-                                {
-                                    addNamedAssociation( stateDescriptor, namedAssocs, associationValue );
-                                }
-                            } ) );
+        sqlTable.fetchAssociations( baseEntity, baseEntity.type, associationValue ->
+        {
+            if( stateDescriptor.hasManyAssociation( associationValue.name ) )
+            {
+                addManyAssociation( stateDescriptor, manyAssocs, associationValue );
+            }
+            else if( stateDescriptor.hasNamedAssociation( associationValue.name ) )
+            {
+                addNamedAssociation( stateDescriptor, namedAssocs, associationValue );
+            }
+        } );
 
         return new DefaultEntityState( baseEntity.version,
                                        baseEntity.modifedAt,
@@ -117,7 +131,7 @@ public class JooqEntityStoreMixin
 
     private void addNamedAssociation( AssociationStateDescriptor stateDescriptor, Map<QualifiedName, Map<String, EntityReference>> namedAssocs, AssociationValue associationValue )
     {
-        AssociationDescriptor descriptor = stateDescriptor.getNamedAssociationByName( associationValue.name );
+        AssociationDescriptor descriptor = stateDescriptor.getNamedAssociationByName( associationValue.name.name() );
         QualifiedName qualifiedName = descriptor.qualifiedName();
         Map<String, EntityReference> map = namedAssocs.computeIfAbsent( qualifiedName, k -> new HashMap<>() );
         map.put( associationValue.position, parseEntityReference( associationValue.reference ) );
@@ -125,10 +139,11 @@ public class JooqEntityStoreMixin
 
     private void addManyAssociation( AssociationStateDescriptor stateDescriptor, Map<QualifiedName, List<EntityReference>> manyAssocs, AssociationValue associationValue )
     {
-        AssociationDescriptor descriptor = stateDescriptor.getManyAssociationByName( associationValue.name );
+        AssociationDescriptor descriptor = stateDescriptor.getManyAssociationByName( associationValue.name.name() );
         QualifiedName qualifiedName = descriptor.qualifiedName();
         List<EntityReference> list = manyAssocs.computeIfAbsent( qualifiedName, k -> new ArrayList<>() );
-        list.add( parseEntityReference( associationValue.reference ) );
+        String reference = associationValue.reference;
+        list.add( reference == null ? null : parseEntityReference( reference ) );
     }
 
     @Override
@@ -158,7 +173,16 @@ public class JooqEntityStoreMixin
     @Override
     public Stream<EntityState> entityStates( ModuleDescriptor module )
     {
-        return null;
+        Stream<? extends EntityDescriptor> entityTypes = module.entityComposites();
+        return entityTypes
+            .flatMap( type -> sqlTable.fetchAll( type, module ) )
+            .map( baseEntity ->
+                  {
+                      EntityReference reference = EntityReference.entityReferenceFor( baseEntity.identity );
+                      SelectQuery<Record> selectQuery = sqlTable.createGetEntityQuery( baseEntity.type, reference );
+                      Result<Record> result = selectQuery.fetch();
+                      return toEntityState( result, baseEntity, reference );
+                  } );
     }
 
     private class JooqStateCommitter
@@ -167,12 +191,36 @@ public class JooqEntityStoreMixin
         private final EntityStoreUnitOfWork unitOfWork;
         private final Iterable<EntityState> states;
         private final JooqDslContext dslContext;
+        private final ModuleDescriptor module;
 
         JooqStateCommitter( EntityStoreUnitOfWork unitOfWork, Iterable<EntityState> states, JooqDslContext dslContext )
         {
             this.unitOfWork = unitOfWork;
             this.states = states;
             this.dslContext = dslContext;
+            this.module = unitOfWork.module();
+        }
+
+        private void newState( DefaultEntityState state, EntityStoreUnitOfWork unitOfWork )
+        {
+            EntityReference ref = state.entityReference();
+            EntityDescriptor descriptor = state.entityDescriptor();
+            sqlTable.createNewBaseEntity( ref, descriptor, this.unitOfWork );
+            sqlTable.insertEntity( state, sqlTable.fetchBaseEntity( ref, module ), unitOfWork );
+        }
+
+        private void updateState( DefaultEntityState state, EntityStoreUnitOfWork unitOfWork )
+        {
+            EntityDescriptor descriptor = state.entityDescriptor();
+            BaseEntity baseEntity = sqlTable.fetchBaseEntity( state.entityReference(), descriptor.module() );
+            sqlTable.updateEntity( state, baseEntity, unitOfWork );
+        }
+
+        private void removeState( DefaultEntityState state )
+        {
+            EntityReference reference = state.entityReference();
+            EntityDescriptor descriptor = state.entityDescriptor();
+            sqlTable.removeEntity( reference, descriptor );
         }
 
         @Override
@@ -185,11 +233,11 @@ public class JooqEntityStoreMixin
                                             DefaultEntityState state = (DefaultEntityState) es;
                                             if( state.status() == EntityStatus.NEW )
                                             {
-                                                newState( state );
+                                                newState( state, unitOfWork );
                                             }
                                             if( state.status() == EntityStatus.UPDATED )
                                             {
-                                                updateState( state );
+                                                updateState( state, unitOfWork );
                                             }
                                             if( state.status() == EntityStatus.REMOVED )
                                             {
@@ -199,24 +247,6 @@ public class JooqEntityStoreMixin
                                     } );
         }
 
-        private void newState( DefaultEntityState state )
-        {
-            EntityReference ref = state.entityReference();
-            EntityDescriptor descriptor = state.entityDescriptor();
-            sqlTable.createNewBaseEntity( ref, descriptor, unitOfWork );
-            sqlTable.insertEntity( state );
-        }
-
-        private void updateState( DefaultEntityState state )
-        {
-
-        }
-
-        private void removeState( DefaultEntityState state )
-        {
-            EntityReference reference = state.entityReference();
-        }
-
         @Override
         public void cancel()
         {

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/MixinTable.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/MixinTable.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/MixinTable.java
index fee95ef..257134e 100644
--- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/MixinTable.java
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/MixinTable.java
@@ -20,7 +20,11 @@ package org.apache.polygene.entitystore.jooq;
 import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.Method;
 import java.sql.Timestamp;
+import java.util.Collections;
+import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.function.Consumer;
 import org.apache.polygene.api.association.AssociationDescriptor;
 import org.apache.polygene.api.common.QualifiedName;
@@ -32,10 +36,12 @@ import org.apache.polygene.spi.entity.NamedAssociationState;
 import org.apache.polygene.spi.entitystore.helpers.DefaultEntityState;
 import org.jooq.Field;
 import org.jooq.InsertSetMoreStep;
+import org.jooq.InsertSetStep;
 import org.jooq.Name;
 import org.jooq.Record;
 import org.jooq.Schema;
 import org.jooq.Table;
+import org.jooq.UpdateSetMoreStep;
 import org.jooq.impl.DSL;
 
 class MixinTable
@@ -46,6 +52,11 @@ class MixinTable
     private final Table<Record> mixinAssocsTable;
 
     private final JooqDslContext dsl;
+    private final Map<QualifiedName, Field<Object>> properties = new ConcurrentHashMap<>();
+    private final Map<QualifiedName, Field<String>> associations = new ConcurrentHashMap<>();
+    private final List<QualifiedName> manyAssociations = new CopyOnWriteArrayList<>();
+    private final List<QualifiedName> namedAssociations = new CopyOnWriteArrayList<>();
+
     private TypesTable types;
     private final Class<?> mixinType;
 
@@ -57,6 +68,34 @@ class MixinTable
         this.mixinType = mixinType;
         mixinTable = types.tableFor( mixinType, descriptor );
         mixinAssocsTable = getAssocsTable( descriptor, schema );
+
+        descriptor.valueType().properties()
+                  .filter( this::isThisMixin )
+                  .forEach( propDescriptor ->
+                            {
+                                QualifiedName propertyName = propDescriptor.qualifiedName();
+                                Field<Object> propertyField = types.fieldOf( propDescriptor );
+                                properties.put( propertyName, propertyField );
+                            }
+                          );
+
+        descriptor.valueType().associations()
+                  .filter( this::isThisMixin )
+                  .forEach( assocDescriptor ->
+                            {
+                                QualifiedName assocName = assocDescriptor.qualifiedName();
+                                Field<String> assocField = types.fieldOf( assocDescriptor );
+                                associations.put( assocName, assocField );
+                            }
+                          );
+
+        descriptor.valueType().manyAssociations()
+                  .filter( this::isThisMixin )
+                  .forEach( assocDescriptor -> manyAssociations.add( assocDescriptor.qualifiedName() ) );
+
+        descriptor.valueType().namedAssociations()
+                  .filter( this::isThisMixin )
+                  .forEach( assocDescriptor -> manyAssociations.add( assocDescriptor.qualifiedName() ) );
     }
 
     void insertMixinState( DefaultEntityState state, String valueIdentity )
@@ -64,93 +103,99 @@ class MixinTable
         InsertSetMoreStep<Record> primaryTable =
             dsl.insertInto( mixinTable )
                .set( identityColumn, valueIdentity )
-               .set( createdColumn, new Timestamp( System.currentTimeMillis() ) )
-               .set( modifiedColumn, new Timestamp( System.currentTimeMillis() ) );
+               .set( createdColumn, new Timestamp( System.currentTimeMillis() ) );
 
-        EntityDescriptor entityDescriptor = state.entityDescriptor();
-        entityDescriptor.valueType().properties()
-                        .filter( this::isThisMixin )
-                        .forEach( propDescriptor ->
+        properties.forEach( ( propertyName, propertyField ) -> primaryTable.set( propertyField, state.propertyValueOf( propertyName ) ) );
+        associations.forEach( ( assocName, assocField ) ->
+                              {
+                                  EntityReference reference = state.associationValueOf( assocName );
+                                  String identity = null;
+                                  if( reference != null )
                                   {
-                                      QualifiedName propertyName = propDescriptor.qualifiedName();
-                                      Field<Object> propertyField = types.fieldOf( propDescriptor );
-                                      primaryTable.set( propertyField, state.propertyValueOf( propertyName ) );
+                                      identity = reference.identity().toString();
                                   }
-                                );
-        entityDescriptor.valueType().associations()
-                        .filter( this::isThisMixin )
-                        .forEach( assocDescriptor ->
-                                  {
-                                      QualifiedName assocName = assocDescriptor.qualifiedName();
-                                      Field<String> assocField = types.fieldOf( assocDescriptor );
-                                      EntityReference reference = state.associationValueOf( assocName );
-                                      String identity = null;
-                                      if( reference != null )
-                                      {
-                                          identity = reference.identity().toString();
-                                      }
-                                      primaryTable.set( assocField, identity );
-                                  }
-                                );
+                                  primaryTable.set( assocField, identity );
+                              }
+                            );
+        int result = primaryTable.execute();
 
         if( mixinAssocsTable != null )
         {
-            entityDescriptor.valueType().manyAssociations()
-                            .filter( this::isThisMixin )
-                            .forEach( setManyAssociations( state, valueIdentity ) );
-
-            entityDescriptor.valueType().namedAssociations()
-                            .filter( this::isThisMixin )
-                            .forEach( setNamedAssociations( state, valueIdentity ) );
+            insertManyAndNamedAssociations( state, valueIdentity );
         }
     }
 
-    private Consumer<? super AssociationDescriptor> setManyAssociations( DefaultEntityState state, String valueIdentity )
+    private void insertManyAndNamedAssociations( DefaultEntityState state, String valueIdentity )
     {
-        return assocDescriptor ->
-        {
-            QualifiedName assocName = assocDescriptor.qualifiedName();
-            ManyAssociationState entityReferences = state.manyAssociationValueOf( assocName );
-            entityReferences.stream().forEach( setManyAssociation( state, assocDescriptor, valueIdentity ) );
-        };
+        InsertSetStep<Record> assocsTable = dsl.insertInto( mixinAssocsTable );
+        manyAssociations.forEach( assocName ->
+                                  {
+                                      ManyAssociationState entityReferences = state.manyAssociationValueOf( assocName );
+                                      entityReferences.stream().forEach( setManyAssociation( assocName, valueIdentity, assocsTable ) );
+                                  } );
+
+        namedAssociations.forEach( assocName ->
+                                   {
+                                       NamedAssociationState entityReferences = state.namedAssociationValueOf( assocName );
+                                       entityReferences.stream().forEach( setNamedAssociation( assocName, valueIdentity, assocsTable ) );
+                                   } );
+
+        InsertSetMoreStep<Record> assocs = assocsTable.set( Collections.emptyMap() );
+        assocs.execute();
     }
 
-    private Consumer<? super EntityReference> setManyAssociation( DefaultEntityState state,
-                                                                  AssociationDescriptor assocDescriptor,
-                                                                  String valueIdentity )
+    Table<Record> associationsTable()
     {
-        QualifiedName assocName = assocDescriptor.qualifiedName();
-        Field<String> assocField = types.fieldOf( assocDescriptor );
-        InsertSetMoreStep<Record> assocsTable = dsl.insertInto( mixinAssocsTable ).set( identityColumn, valueIdentity );
-        return ref ->
-        {
-            assocsTable.newRecord();
-            assocsTable.set( assocField, state.associationValueOf( assocName ).identity().toString() );
-        };
+        return mixinAssocsTable;
     }
 
-    private Consumer<? super AssociationDescriptor> setNamedAssociations( DefaultEntityState state,
-                                                                          String valueIdentity )
+    /**
+     * Writes one ManyAssoc Reference to the _ASSOCS table.
+     * <ul>
+     * <li>identityColumn - valueIdentity of primaryTable row</li>
+     * <li>nameColumn - index in the of association in state holder</li>
+     * <li>indexColumn - the position within the many association, starting at 0</li>
+     * <li>referenceColumn - referenced entity's identity</li>
+     * </ul>
+     */
+    private Consumer<? super EntityReference> setManyAssociation( QualifiedName assocName,
+                                                                  String valueIdentity,
+                                                                  InsertSetStep<Record> assocsTable )
     {
-        return assocDescriptor ->
+        return new Consumer<EntityReference>()
         {
-            QualifiedName assocName = assocDescriptor.qualifiedName();
-            NamedAssociationState entityReferences = state.namedAssociationValueOf( assocName );
-            entityReferences.stream().forEach( setNamedAssociation( state, assocDescriptor, valueIdentity ) );
+            private int counter = 0;
+
+            @Override
+            public void accept( EntityReference ref )
+            {
+                InsertSetMoreStep<Record> set = assocsTable.set( identityColumn, valueIdentity )
+                                                           .set( nameColumn, assocName.name() )
+                                                           .set( indexColumn, "" + counter++ )
+                                                           .set( referenceColumn, ref == null ? null : ref.identity().toString() );
+            }
         };
     }
 
-    private Consumer<? super Map.Entry<String, EntityReference>> setNamedAssociation( DefaultEntityState state,
-                                                                                      AssociationDescriptor assocDescriptor,
-                                                                                      String valueIdentity )
+    /**
+     * Writes one Named Reference to the _ASSOCS table.
+     * <ul>
+     * <li>identityColumn - valueIdentity of primaryTable row</li>
+     * <li>nameColumn - name of association in state holder</li>
+     * <li>indexColumn - the key/lookup name of the reference</li>
+     * <li>referenceColumn - referenced entity's identity</li>
+     * </ul>
+     */
+    private Consumer<? super Map.Entry<String, EntityReference>> setNamedAssociation( QualifiedName assocName,
+                                                                                      String valueIdentity,
+                                                                                      InsertSetStep<Record> assocsTable )
     {
-        QualifiedName assocName = assocDescriptor.qualifiedName();
-        Field<String> assocField = types.fieldOf( assocDescriptor );
-        InsertSetMoreStep<Record> assocsTable = dsl.insertInto( mixinAssocsTable ).set( identityColumn, valueIdentity );
         return ref ->
         {
-            assocsTable.newRecord();
-            assocsTable.set( assocField, state.associationValueOf( assocName ).identity().toString() );
+            InsertSetMoreStep<Record> set = assocsTable.set( identityColumn, valueIdentity )
+                                                       .set( nameColumn, assocName.name() )
+                                                       .set( indexColumn, ref.getKey() )
+                                                       .set( referenceColumn, ref.getValue().identity().toString() );
         };
     }
 
@@ -186,9 +231,31 @@ class MixinTable
         throw new UnsupportedOperationException( "Property declared as " + accessor.getClass() + " is not supported in this Entity Store yet." );
     }
 
-    void modifyMixinState( Class<?> mixinType, DefaultEntityState state )
+    void modifyMixinState( DefaultEntityState state, String valueId )
     {
+        UpdateSetMoreStep<Record> primaryTable =
+            dsl.update( mixinTable )
+               .set( Collections.emptyMap() );  // empty map is a hack to get the right type returned from JOOQ.
+
+        properties.forEach( ( propertyName, propertyField ) -> primaryTable.set( propertyField, state.propertyValueOf( propertyName ) ) );
+        associations.forEach( ( assocName, assocField ) ->
+                              {
+                                  EntityReference reference = state.associationValueOf( assocName );
+                                  primaryTable.set( assocField,
+                                                    reference == null ? null : reference.identity().toString()
+                                                  );
+                              }
+                            );
+        int result = primaryTable.execute();
 
+        if( mixinAssocsTable != null )
+        {
+            // Need to remove existing records.
+            dsl.delete( mixinAssocsTable )
+               .where( identityColumn.eq( valueId ) )
+               .execute();
+            insertManyAndNamedAssociations( state, valueId );
+        }
     }
 
     private Table<Record> getAssocsTable( EntityDescriptor descriptor, Schema schema )

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlTable.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlTable.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlTable.java
index 2801f57..13b6c37 100644
--- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlTable.java
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/SqlTable.java
@@ -18,6 +18,7 @@
 package org.apache.polygene.entitystore.jooq;
 
 import java.util.function.Consumer;
+import java.util.stream.Stream;
 import javax.sql.DataSource;
 import org.apache.polygene.api.PolygeneAPI;
 import org.apache.polygene.api.composite.TransientBuilderFactory;
@@ -99,14 +100,20 @@ public interface SqlTable extends ServiceActivation
 
     SelectQuery<Record> createGetEntityQuery( EntityDescriptor descriptor, EntityReference reference );
 
-    void fetchAssociations( Record record, Consumer<AssociationValue> consume );
+    void fetchAssociations( BaseEntity entity, EntityDescriptor descriptor, Consumer<AssociationValue> consume );
 
     void createNewBaseEntity( EntityReference ref, EntityDescriptor descriptor, EntityStoreUnitOfWork unitOfWork );
 
-    void insertEntity( DefaultEntityState state );
+    void insertEntity( DefaultEntityState state, BaseEntity baseEntity, EntityStoreUnitOfWork unitOfWork );
+
+    void updateEntity( DefaultEntityState state, BaseEntity baseEntity, EntityStoreUnitOfWork unitOfWork );
 
     JooqDslContext jooqDslContext();
 
+    void removeEntity( EntityReference entityReference, EntityDescriptor descriptor );
+
+    Stream<BaseEntity> fetchAll( EntityDescriptor type, ModuleDescriptor module );
+
     class Mixin
         implements SqlTable, TableFields, ServiceActivation
     {
@@ -143,15 +150,21 @@ public interface SqlTable extends ServiceActivation
         }
 
         @Override
+        public Stream<BaseEntity> fetchAll( EntityDescriptor type, ModuleDescriptor module )
+        {
+            return entitiesTable.fetchAll( type, module );
+        }
+
+        @Override
         public SelectQuery<Record> createGetEntityQuery( EntityDescriptor descriptor, EntityReference reference )
         {
             return entitiesTable.createGetEntityQuery( descriptor, reference );
         }
 
         @Override
-        public void fetchAssociations( Record record, Consumer<AssociationValue> consume )
+        public void fetchAssociations( BaseEntity entity, EntityDescriptor descriptor, Consumer<AssociationValue> consume )
         {
-            entitiesTable.fetchAssociations( record, consume );
+            entitiesTable.fetchAssociations( entity, descriptor, consume );
         }
 
         @Override
@@ -161,9 +174,15 @@ public interface SqlTable extends ServiceActivation
         }
 
         @Override
-        public void insertEntity( DefaultEntityState state )
+        public void insertEntity( DefaultEntityState state, BaseEntity baseEntity, EntityStoreUnitOfWork unitOfWork )
         {
-            entitiesTable.insertEntity( state );
+            entitiesTable.insertEntity( state, baseEntity );
+        }
+
+        @Override
+        public void updateEntity( DefaultEntityState state, BaseEntity baseEntity, EntityStoreUnitOfWork unitOfWork )
+        {
+            entitiesTable.modifyEntity( state, baseEntity, unitOfWork );
         }
 
         @Override
@@ -173,6 +192,12 @@ public interface SqlTable extends ServiceActivation
         }
 
         @Override
+        public void removeEntity( EntityReference reference, EntityDescriptor descriptor )
+        {
+            entitiesTable.removeEntity( reference, descriptor );
+        }
+
+        @Override
         public void activateService()
             throws Exception
         {

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TableFields.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TableFields.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TableFields.java
index 2454ae4..db42413 100644
--- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TableFields.java
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TableFields.java
@@ -25,23 +25,23 @@ import static org.apache.polygene.entitystore.jooq.TypesTable.makeField;
 public interface TableFields
 {
     // Common in all tables
-    String IDENTITY_COLUMN_NAME = "identity";
-    String CREATED_COLUMN_NAME = "created_at";
-    String LASTMODIFIED_COLUMN_NAME = "modified_at";
+    String IDENTITY_COLUMN_NAME = "_identity";
+    String CREATED_COLUMN_NAME = "_created_at";
+    String LASTMODIFIED_COLUMN_NAME = "_modified_at";
 
     // Types Table
-    String TABLENAME_COLUMN_NAME = "table_name";
+    String TABLENAME_COLUMN_NAME = "_table_name";
 
     // Entities Table
-    String VALUEID_COLUMN_NAME = "value_id";
-    String TYPE_COLUMN_NAME = "type";
-    String VERSION_COLUMN_NAME = "version";
-    String APPLICATIONVERSION_COLUMN_NAME = "app_version";
+    String VALUEID_COLUMN_NAME = "_value_id";
+    String TYPE_COLUMN_NAME = "_type";
+    String VERSION_COLUMN_NAME = "_version";
+    String APPLICATIONVERSION_COLUMN_NAME = "_app_version";
 
     // Mixin Tables
-    String NAME_COLUMN_NAME = "name";
-    String INDEX_COLUMN_NAME = "index";    // either index in ManyAssociation or name in NamedAssociation
-    String REFERENCE_COLUMN_NAME = "reference";
+    String NAME_COLUMN_NAME = "_name";
+    String INDEX_COLUMN_NAME = "_index";    // either index in ManyAssociation or name in NamedAssociation
+    String REFERENCE_COLUMN_NAME = "_reference";
     String ASSOCS_TABLE_POSTFIX = "_ASSOCS";
 
 

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TypesTable.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TypesTable.java b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TypesTable.java
index 4672d4f..c816c95 100644
--- a/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TypesTable.java
+++ b/extensions/entitystore-jooq/src/main/java/org/apache/polygene/entitystore/jooq/TypesTable.java
@@ -110,12 +110,14 @@ public class TypesTable
     {
         String mixinTypeName = mixinType.getName();
         String tableName = createNewTableName( mixinType );
-        CreateTableColumnStep primaryTable = dsl.createTable( tableName ).column( identityColumn );
+        CreateTableColumnStep primaryTable = dsl.createTable( DSL.name( schema.getName(), tableName ) )
+                                                .column( identityColumn )
+                                                .column( createdColumn );
         descriptor.state().properties().forEach(
             property ->
             {
                 QualifiedName qualifiedName = property.qualifiedName();
-                if( qualifiedName.toNamespace().equals( mixinTypeName ) )
+                if( qualifiedName.type().replace( '-', '$' ).equals( mixinTypeName ) )
                 {
                     primaryTable.column( fieldOf( property ) );
                 }
@@ -124,12 +126,12 @@ public class TypesTable
             assoc ->
             {
                 QualifiedName qualifiedName = assoc.qualifiedName();
-                if( qualifiedName.toNamespace().equals( mixinTypeName ) )
+                if( qualifiedName.type().replace( '-', '$' ).equals( mixinTypeName ) )
                 {
                     primaryTable.column( fieldOf( assoc ) );
                 }
             } );
-
+        int result1 = primaryTable.execute();
         int result3 = dsl.insertInto( typesTable )
                          .set( identityColumn, mixinTypeName )
                          .set( tableNameColumn, tableName )

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/extensions/entitystore-jooq/src/test/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreTest.java
----------------------------------------------------------------------
diff --git a/extensions/entitystore-jooq/src/test/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreTest.java b/extensions/entitystore-jooq/src/test/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreTest.java
index e097662..f36db0e 100644
--- a/extensions/entitystore-jooq/src/test/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreTest.java
+++ b/extensions/entitystore-jooq/src/test/java/org/apache/polygene/entitystore/jooq/JooqEntityStoreTest.java
@@ -29,22 +29,13 @@ import org.apache.polygene.library.sql.dbcp.DBCPDataSourceServiceAssembler;
 import org.apache.polygene.test.EntityTestAssembler;
 import org.apache.polygene.test.entity.AbstractEntityStoreTest;
 import org.jooq.SQLDialect;
+import org.junit.Rule;
+import org.junit.rules.TemporaryFolder;
 
 public class JooqEntityStoreTest extends AbstractEntityStoreTest
 {
-//    @ClassRule
-//    public static final DockerRule DOCKER = new DockerRule(
-//        "mysql",
-//        new HashMap<String, String>()
-//        {{
-//            put( "MYSQL_ROOT_PASSWORD", "" );
-//            put( "MYSQL_ALLOW_EMPTY_PASSWORD", "yes" );
-//            put( "MYSQL_DATABASE", "jdbc_test_db" );
-//            put( "MYSQL_ROOT_HOST", "127.0.0.1" );
-//        }},
-//        30000L
-////        , "mysqld: ready for connections"   TODO: add this after next release of tdomzal/junit-docker-rule
-//    );
+    @Rule
+    public final TemporaryFolder tmpDir = new TemporaryFolder();
 
     @Override
     // START SNIPPET: assembly
@@ -83,8 +74,6 @@ public class JooqEntityStoreTest extends AbstractEntityStoreTest
                                                           .declareDefaults();
         jooqDefaults.entitiesTableName().set( "ENTITIES" );
 
-        String path = System.getProperty( "user.dir" ) + "/testdb";
-        System.out.println("Niclas: " + path);
         DataSourceConfiguration dsDefaults = config.forMixin( DataSourceConfiguration.class ).declareDefaults();
         dsDefaults.driver().set( org.h2.Driver.class.getName() );
         dsDefaults.enabled().set( true );
@@ -92,7 +81,7 @@ public class JooqEntityStoreTest extends AbstractEntityStoreTest
         dsDefaults.minPoolSize().set( 1 );
         dsDefaults.username().set( "" );
         dsDefaults.password().set( "" );
-        dsDefaults.url().set( "jdbc:h2:"+path+";create=true" );
+        dsDefaults.url().set( "jdbc:h2:" + tmpDir.getRoot().getAbsolutePath() + "/testdb;create=true" );
         // START SNIPPET: assembly
     }
     // END SNIPPET: assembly

http://git-wip-us.apache.org/repos/asf/polygene-java/blob/59a08629/manual/src/docs/userguide/extensions.txt
----------------------------------------------------------------------
diff --git a/manual/src/docs/userguide/extensions.txt b/manual/src/docs/userguide/extensions.txt
index 44bfd3f..5026259 100644
--- a/manual/src/docs/userguide/extensions.txt
+++ b/manual/src/docs/userguide/extensions.txt
@@ -105,6 +105,10 @@ include::../../../../extensions/entitystore-riak/src/docs/es-riak.txt[]
 
 :leveloffset: 2
 
+include::../../../../extensions/entitystore-jooq/src/docs/es-jooq.txt[]
+
+:leveloffset: 2
+
 include::../../../../extensions/entitystore-sql/src/docs/es-sql.txt[]
 
 :leveloffset: 2