From bc5c37e02a2e73be7ef87445110ab474952c7d84 Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Thu, 2 Nov 2023 17:30:14 +0100 Subject: [PATCH] [DEV] continue works --- .../archidata/annotation/AnnotationTools.java | 29 +++- .../kar/archidata/dataAccess/DataAccess.java | 151 ++++++++---------- .../archidata/dataAccess/DataAccessAddOn.java | 12 +- .../archidata/dataAccess/QueryOptions.java | 16 ++ .../dataAccess/addOn/AddOnManyToMany.java | 13 +- .../addOn/AddOnManyToManyOrdered.java | 13 +- .../dataAccess/addOn/AddOnManyToOne.java | 124 +++++++------- .../dataAccess/addOn/AddOnOneToMany.java | 129 +++++++++++++++ .../AddOnSQLTableExternalForeinKeyAsList.java | 28 ++-- .../test/kar/archidata/TestManyToMany.java | 55 ++++--- .../src/test/kar/archidata/TestManyToOne.java | 85 ++++++++++ .../src/test/kar/archidata/TestOneToMany.java | 62 +++++++ .../model/TypeManyToManyRootExpand.java | 20 +++ .../archidata/model/TypeManyToOneRemote.java | 16 ++ .../archidata/model/TypeManyToOneRoot.java | 20 +++ .../model/TypeManyToOneRootExpand.java | 21 +++ 16 files changed, 575 insertions(+), 219 deletions(-) create mode 100644 src/org/kar/archidata/dataAccess/addOn/AddOnOneToMany.java create mode 100644 test/src/test/kar/archidata/TestManyToOne.java create mode 100644 test/src/test/kar/archidata/TestOneToMany.java create mode 100644 test/src/test/kar/archidata/model/TypeManyToManyRootExpand.java create mode 100644 test/src/test/kar/archidata/model/TypeManyToOneRemote.java create mode 100644 test/src/test/kar/archidata/model/TypeManyToOneRoot.java create mode 100644 test/src/test/kar/archidata/model/TypeManyToOneRootExpand.java diff --git a/src/org/kar/archidata/annotation/AnnotationTools.java b/src/org/kar/archidata/annotation/AnnotationTools.java index 1cd7c17..0e661f9 100644 --- a/src/org/kar/archidata/annotation/AnnotationTools.java +++ b/src/org/kar/archidata/annotation/AnnotationTools.java @@ -206,13 +206,13 @@ public class AnnotationTools { public static Field getIdField(final Class clazz) { try { - for (final Field elem : clazz.getFields()) { + for (final Field field : clazz.getFields()) { // static field is only for internal global declaration ==> remove it .. - if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { + if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) { continue; } - if (AnnotationTools.isIdField(elem)) { - return elem; + if (AnnotationTools.isIdField(field)) { + return field; } } } catch (final Exception ex) { @@ -231,15 +231,15 @@ public class AnnotationTools { private static List getFieldsNamesFilter(final Class clazz, final boolean full) throws Exception { final List out = new ArrayList<>(); - for (final Field elem : clazz.getFields()) { + for (final Field field : clazz.getFields()) { // static field is only for internal global declaration ==> remove it .. - if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { + if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) { continue; } - if (!full && AnnotationTools.isGenericField(elem)) { + if (!full && AnnotationTools.isGenericField(field)) { continue; } - out.add(AnnotationTools.getFieldName(elem)); + out.add(AnnotationTools.getFieldName(field)); } return out; } @@ -248,4 +248,17 @@ public class AnnotationTools { return AnnotationTools.isPrimaryKey(elem) || AnnotationTools.isCreatedAtField(elem) || AnnotationTools.isUpdateAtField(elem); } + public static Field getFieldOfId(final Class clazz) throws Exception { + for (final Field field : clazz.getFields()) { + // static field is only for internal global declaration ==> remove it .. + if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) { + continue; + } + if (AnnotationTools.isIdField(field)) { + return field; + } + } + return null; + } + } diff --git a/src/org/kar/archidata/dataAccess/DataAccess.java b/src/org/kar/archidata/dataAccess/DataAccess.java index 63c22b8..86628f2 100644 --- a/src/org/kar/archidata/dataAccess/DataAccess.java +++ b/src/org/kar/archidata/dataAccess/DataAccess.java @@ -469,7 +469,7 @@ public class DataAccess { continue; } final DataAccessAddOn addOn = findAddOnforField(elem); - if (addOn != null && !addOn.canInsert()) { + if (addOn != null && !addOn.canInsert(elem)) { continue; } final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0; @@ -523,7 +523,7 @@ public class DataAccess { continue; } final DataAccessAddOn addOn = findAddOnforField(elem); - if (addOn != null && !addOn.canInsert()) { + if (addOn != null && !addOn.canInsert(elem)) { continue; } final boolean createTime = elem.getDeclaredAnnotationsByType(CreationTimestamp.class).length != 0; @@ -536,8 +536,7 @@ public class DataAccess { } if (addOn != null) { // Add-on specific insertion. - final Object tmp = elem.get(data); - iii = addOn.insertData(ps, tmp, iii); + iii = addOn.insertData(ps, elem, data, iii); } else { // Generic class insertion... final Class type = elem.getType(); @@ -663,10 +662,10 @@ public class DataAccess { if (id == typeClass) { throw new Exception("Request update with the wriong type ..."); } - return update(data, new QueryCondition(AnnotationTools.getFieldName(idField), "=", id), filterValue); + return updateWhere(data, new QueryCondition(AnnotationTools.getFieldName(idField), "=", id), null, filterValue); } - public static int update(final T data, final QueryItem condition, final QueryOptions options, final List filterValue) throws Exception { + public static int updateWhere(final T data, final QueryItem condition, final QueryOptions options, final List filterValue) throws Exception { final Class clazz = data.getClass(); //public static NodeSmall createNode(String typeInNode, String name, String description, Long parentId) { @@ -681,26 +680,26 @@ public class DataAccess { querry.append("` SET "); boolean firstField = true; - for (final Field elem : clazz.getFields()) { + for (final Field field : clazz.getFields()) { // static field is only for internal global declaration ==> remove it .. - if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { + if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) { continue; } - final String name = AnnotationTools.getFieldName(elem); + final String name = AnnotationTools.getFieldName(field); if (filterValue != null) { if (!filterValue.contains(name)) { continue; } - } else if (AnnotationTools.isGenericField(elem)) { + } else if (AnnotationTools.isGenericField(field)) { continue; } - final DataAccessAddOn addOn = findAddOnforField(elem); - if (addOn != null && !addOn.canUpdate()) { + final DataAccessAddOn addOn = findAddOnforField(field); + if (addOn != null && !addOn.canInsert(field)) { continue; } - if (!elem.getClass().isPrimitive()) { - final Object tmp = elem.get(data); - if (tmp == null && elem.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) { + if (!field.getClass().isPrimitive()) { + final Object tmp = field.get(data); + if (tmp == null && field.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) { continue; } } @@ -721,34 +720,34 @@ public class DataAccess { // prepare the request: final PreparedStatement ps = entry.connection.prepareStatement(querry.toString(), Statement.RETURN_GENERATED_KEYS); int iii = 1; - for (final Field elem : clazz.getFields()) { + for (final Field field : clazz.getFields()) { // static field is only for internal global declaration ==> remove it .. - if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { + if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) { continue; } - final String name = AnnotationTools.getFieldName(elem); + final String name = AnnotationTools.getFieldName(field); if (filterValue != null) { if (!filterValue.contains(name)) { continue; } - } else if (AnnotationTools.isGenericField(elem)) { + } else if (AnnotationTools.isGenericField(field)) { continue; } - final DataAccessAddOn addOn = findAddOnforField(elem); - if (addOn != null && !addOn.canUpdate()) { + final DataAccessAddOn addOn = findAddOnforField(field); + if (addOn != null && !addOn.canInsert(field)) { continue; } if (addOn == null) { - final Class type = elem.getType(); + final Class type = field.getType(); if (!type.isPrimitive()) { - final Object tmp = elem.get(data); - if (tmp == null && elem.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) { + final Object tmp = field.get(data); + if (tmp == null && field.getDeclaredAnnotationsByType(SQLDefault.class).length != 0) { continue; } } - setValuedb(type, data, iii++, elem, ps); + setValuedb(type, data, iii++, field, ps); } else { - iii = addOn.insertData(ps, data, iii); + iii = addOn.insertData(ps, field, data, iii); } } iii = whereInjectValue(ps, condition, iii); @@ -885,78 +884,68 @@ public class DataAccess { return getsWhere(clazz, condition, null, options, linit); } + public static int generateSelectField(final StringBuilder querry, final Class clazz, final QueryOptions options, int count) throws Exception { + final boolean readAllfields = QueryOptions.readAllFields(options); + final String tableName = AnnotationTools.getTableName(clazz, options); + boolean firstField = true; + for (final Field elem : clazz.getFields()) { + // static field is only for internal global declaration ==> remove it .. + if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { + continue; + } + final DataAccessAddOn addOn = findAddOnforField(elem); + if (addOn != null && !addOn.canRetrieve(elem)) { + continue; + } + // TODO: Manage it with AddOn + final boolean notRead = AnnotationTools.isdefaultNotRead(elem); + if (!readAllfields && notRead) { + continue; + } + final String name = AnnotationTools.getFieldName(elem); + count++; + if (firstField) { + firstField = false; + } else { + querry.append(","); + } + querry.append(" "); + if (addOn != null) { + count = addOn.generateQuerry(tableName, elem, querry, name, count, options); + } else { + querry.append(tableName); + querry.append("."); + querry.append(name); + } + } + querry.append(" FROM `"); + querry.append(tableName); + querry.append("` "); + return count; + } + // TODO: set limit as an query Option... @SuppressWarnings("unchecked") public static List getsWhere(final Class clazz, final QueryItem condition, final String orderBy, final QueryOptions options, final Integer linit) throws Exception { - - boolean readAllfields = false; - if (options != null) { - final Object data = options.get(QueryOptions.SQL_NOT_READ_DISABLE); - if (data instanceof final Boolean elem) { - readAllfields = elem; - } else if (data != null) { - LOGGER.error("'{}' ==> has not a boolean value: {}", QueryOptions.SQL_NOT_READ_DISABLE, data); - } - } - + final boolean readAllfields = QueryOptions.readAllFields(options); + final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); final List outs = new ArrayList<>(); // real add in the BDD: try { - final String tableName = AnnotationTools.getTableName(clazz, options); - //boolean createIfNotExist = clazz.getDeclaredAnnotationsByType(SQLIfNotExists.class).length != 0; + int count = 0; final StringBuilder querry = new StringBuilder(); querry.append("SELECT "); - //querry.append(tableName); - //querry.append(" SET "); - - boolean firstField = true; - int count = 0; - final String deletedFieldName = AnnotationTools.getDeletedFieldName(clazz); - for (final Field elem : clazz.getFields()) { - // static field is only for internal global declaration ==> remove it .. - if (java.lang.reflect.Modifier.isStatic(elem.getModifiers())) { - continue; - } - final DataAccessAddOn addOn = findAddOnforField(elem); - if (addOn != null && !addOn.canRetrieve(elem)) { - continue; - } - // TODO: Manage it with AddOn - final boolean notRead = AnnotationTools.isdefaultNotRead(elem); - if (!readAllfields && notRead) { - continue; - } - final String name = AnnotationTools.getFieldName(elem); - count++; - if (firstField) { - firstField = false; - } else { - querry.append(","); - } - querry.append(" "); - if (addOn != null) { - addOn.generateQuerry(tableName, elem, querry, name, count, options); - } else { - querry.append(tableName); - querry.append("."); - querry.append(name); - } - } - querry.append(" FROM `"); - querry.append(tableName); - querry.append("` "); + count = generateSelectField(querry, clazz, options, count); + final String tableName = AnnotationTools.getTableName(clazz, options); whereAppendQuery(querry, tableName, condition, options, deletedFieldName); if (orderBy != null && orderBy.length() >= 1) { querry.append(" ORDER BY "); - //querry.append(tableName); - //querry.append("."); querry.append(orderBy); } if (linit != null && linit >= 1) { querry.append(" LIMIT " + linit); } - firstField = true; LOGGER.debug("generate the querry: '{}'", querry.toString()); // prepare the request: final PreparedStatement ps = entry.connection.prepareStatement(querry.toString(), Statement.RETURN_GENERATED_KEYS); diff --git a/src/org/kar/archidata/dataAccess/DataAccessAddOn.java b/src/org/kar/archidata/dataAccess/DataAccessAddOn.java index 2c95a1a..31c0aa6 100644 --- a/src/org/kar/archidata/dataAccess/DataAccessAddOn.java +++ b/src/org/kar/archidata/dataAccess/DataAccessAddOn.java @@ -37,20 +37,18 @@ public interface DataAccessAddOn { * @return the new index of injection in case of multiple value management * @throws SQLException */ - int insertData(PreparedStatement ps, Object data, int iii) throws SQLException; + int insertData(PreparedStatement ps, final Field field, Object data, int iii) throws Exception, SQLException, IllegalArgumentException, IllegalAccessException; // Element can insert in the single request - boolean canInsert(); + boolean canInsert(final Field field); // Element can be retrieve with the specific mode boolean canRetrieve(final Field field); - int generateQuerry(@NotNull String tableName, @NotNull Field elem, @NotNull StringBuilder querry, @NotNull String name, @NotNull int elemCount, QueryOptions options); + int generateQuerry(@NotNull String tableName, @NotNull Field field, @NotNull StringBuilder querry, @NotNull String name, @NotNull int elemCount, QueryOptions options) throws Exception; // Return the number of colomn read - int fillFromQuerry(ResultSet rs, Field elem, Object data, int count, QueryOptions options) throws SQLException, IllegalArgumentException, IllegalAccessException; - - boolean canUpdate(); + int fillFromQuerry(ResultSet rs, Field field, Object data, int count, QueryOptions options) throws SQLException, IllegalArgumentException, IllegalAccessException; /** * Create associated table of the specific element. @@ -63,7 +61,7 @@ public interface DataAccessAddOn { * @param fieldId * @throws Exception */ - void createTables(String tableName, Field elem, StringBuilder mainTableBuilder, List preActionList, List postActionList, boolean createIfNotExist, boolean createDrop, int fieldId) + void createTables(String tableName, Field field, StringBuilder mainTableBuilder, List preActionList, List postActionList, boolean createIfNotExist, boolean createDrop, int fieldId) throws Exception; } diff --git a/src/org/kar/archidata/dataAccess/QueryOptions.java b/src/org/kar/archidata/dataAccess/QueryOptions.java index 3370439..a871f06 100644 --- a/src/org/kar/archidata/dataAccess/QueryOptions.java +++ b/src/org/kar/archidata/dataAccess/QueryOptions.java @@ -3,7 +3,11 @@ package org.kar.archidata.dataAccess; import java.util.HashMap; import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class QueryOptions { + static final Logger LOGGER = LoggerFactory.getLogger(QueryOptions.class); public static final String SQL_NOT_READ_DISABLE = "SQLNotRead_disable"; public static final String SQL_DELETED_DISABLE = "SQLDeleted_disable"; public static final String OVERRIDE_TABLE_NAME = "SQL_OVERRIDE_TABLE_NAME"; @@ -37,5 +41,17 @@ public class QueryOptions { public Object get(final String value) { return this.options.get(value); } + + public static boolean readAllFields(final QueryOptions options) { + if (options != null) { + final Object data = options.get(QueryOptions.SQL_NOT_READ_DISABLE); + if (data instanceof final Boolean elem) { + return elem; + } else if (data != null) { + LOGGER.error("'{}' ==> has not a boolean value: {}", QueryOptions.SQL_NOT_READ_DISABLE, data); + } + } + return false; + } } diff --git a/src/org/kar/archidata/dataAccess/addOn/AddOnManyToMany.java b/src/org/kar/archidata/dataAccess/addOn/AddOnManyToMany.java index 6d5df0f..1e31374 100644 --- a/src/org/kar/archidata/dataAccess/addOn/AddOnManyToMany.java +++ b/src/org/kar/archidata/dataAccess/addOn/AddOnManyToMany.java @@ -42,12 +42,12 @@ public class AddOnManyToMany implements DataAccessAddOn { } @Override - public int insertData(final PreparedStatement ps, final Object data, final int iii) throws SQLException { + public int insertData(final PreparedStatement ps, final Field field, final Object rootObject, final int iii) throws SQLException, IllegalArgumentException, IllegalAccessException { return iii; } @Override - public boolean canInsert() { + public boolean canInsert(final Field field) { return false; } @@ -123,11 +123,6 @@ public class AddOnManyToMany implements DataAccessAddOn { return 1; } - @Override - public boolean canUpdate() { - return false; - } - public static void addLink(final Class clazz, final long localKey, final String column, final long remoteKey) throws Exception { final String tableName = AnnotationTools.getTableName(clazz); final String linkTableName = generateLinkTableName(tableName, column); @@ -146,9 +141,9 @@ public class AddOnManyToMany implements DataAccessAddOn { } @Override - public void createTables(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List preActionList, final List postActionList, + public void createTables(final String tableName, final Field field, final StringBuilder mainTableBuilder, final List preActionList, final List postActionList, final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception { - final String linkTableName = generateLinkTableNameField(tableName, elem); + final String linkTableName = generateLinkTableNameField(tableName, field); final QueryOptions options = new QueryOptions(QueryOptions.OVERRIDE_TABLE_NAME, linkTableName); final List sqlCommand = DataFactory.createTable(LinkTable.class, options); postActionList.addAll(sqlCommand); diff --git a/src/org/kar/archidata/dataAccess/addOn/AddOnManyToManyOrdered.java b/src/org/kar/archidata/dataAccess/addOn/AddOnManyToManyOrdered.java index ac69fa3..38589ea 100644 --- a/src/org/kar/archidata/dataAccess/addOn/AddOnManyToManyOrdered.java +++ b/src/org/kar/archidata/dataAccess/addOn/AddOnManyToManyOrdered.java @@ -46,12 +46,12 @@ public class AddOnManyToManyOrdered implements DataAccessAddOn { } @Override - public int insertData(final PreparedStatement ps, final Object data, final int iii) throws SQLException { + public int insertData(final PreparedStatement ps, final Field field, final Object rootObject, final int iii) throws SQLException, IllegalArgumentException, IllegalAccessException { return iii; } @Override - public boolean canInsert() { + public boolean canInsert(final Field field) { return false; } @@ -114,11 +114,6 @@ public class AddOnManyToManyOrdered implements DataAccessAddOn { return 0; } - @Override - public boolean canUpdate() { - return false; - } - public static void addLink(final Class clazz, final long localKey, final String table, final long remoteKey) throws Exception { final String tableName = AnnotationTools.getTableName(clazz); DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); @@ -180,9 +175,9 @@ public class AddOnManyToManyOrdered implements DataAccessAddOn { // TODO : refacto this table to manage a generic table with dynamic name to be serializable with the default system @Override - public void createTables(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List preActionList, final List postActionList, + public void createTables(final String tableName, final Field field, final StringBuilder mainTableBuilder, final List preActionList, final List postActionList, final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception { - final String name = AnnotationTools.getFieldName(elem); + final String name = AnnotationTools.getFieldName(field); String localName = name; if (name.endsWith("s")) { localName = name.substring(0, name.length() - 1); diff --git a/src/org/kar/archidata/dataAccess/addOn/AddOnManyToOne.java b/src/org/kar/archidata/dataAccess/addOn/AddOnManyToOne.java index 295dfd5..2b3a6c7 100644 --- a/src/org/kar/archidata/dataAccess/addOn/AddOnManyToOne.java +++ b/src/org/kar/archidata/dataAccess/addOn/AddOnManyToOne.java @@ -5,11 +5,10 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; -import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; import org.kar.archidata.annotation.AnnotationTools; +import org.kar.archidata.dataAccess.DataAccess; import org.kar.archidata.dataAccess.DataAccessAddOn; import org.kar.archidata.dataAccess.DataFactory; import org.kar.archidata.dataAccess.QueryOptions; @@ -21,43 +20,12 @@ import jakarta.validation.constraints.NotNull; public class AddOnManyToOne implements DataAccessAddOn { static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToMany.class); - - /** - * Convert the list if external id in a string '-' separated - * @param ids List of value (null are removed) - * @return '-' string separated - */ - protected static String getStringOfIds(final List ids) { - final List tmp = new ArrayList<>(ids); - return tmp.stream().map(String::valueOf).collect(Collectors.joining("-")); - } - - /** - * extract a list of "-" separated element from a SQL input data. - * @param rs Result Set of the BDD - * @param iii Id in the result set - * @return The list of Long value - * @throws SQLException if an error is generated in the sql request. - */ - protected static List getListOfIds(final ResultSet rs, final int iii) throws SQLException { - final String trackString = rs.getString(iii); - if (rs.wasNull()) { - return null; - } - final List out = new ArrayList<>(); - final String[] elements = trackString.split("-"); - for (final String elem : elements) { - final Long tmp = Long.parseLong(elem); - out.add(tmp); - } - return out; - } - + @Override public Class getAnnotationClass() { return ManyToOne.class; } - + @Override public String getSQLFieldType(final Field elem) throws Exception { final String fieldName = AnnotationTools.getFieldName(elem); @@ -69,65 +37,91 @@ public class AddOnManyToOne implements DataAccessAddOn { } return null; } - + @Override public boolean isCompatibleField(final Field elem) { final ManyToOne decorators = elem.getDeclaredAnnotation(ManyToOne.class); return decorators != null; } - + @Override - public int insertData(final PreparedStatement ps, final Object data, int iii) throws SQLException { + public int insertData(final PreparedStatement ps, final Field field, final Object rootObject, int iii) throws Exception { + final Object data = field.get(rootObject); if (data == null) { ps.setNull(iii++, Types.BIGINT); + } else if (field.getType() == Long.class) { + final Long dataLong = (Long) data; + ps.setLong(iii++, dataLong); } else { - @SuppressWarnings("unchecked") - final String dataTmp = getStringOfIds((List) data); - ps.setString(iii++, dataTmp); + final Field idField = AnnotationTools.getFieldOfId(field.getType()); + final Object uid = idField.get(data); + if (uid == null) { + ps.setNull(iii++, Types.BIGINT); + throw new Exception("Not implemented adding subClasses ==> add it manualy before..."); + } else { + final Long dataLong = (Long) uid; + ps.setLong(iii++, dataLong); + } } return iii++; } + + @Override + public boolean canInsert(final Field field) { + if (field.getType() == Long.class) { + return true; + } + final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class); + if (field.getType() == decorators.targetEntity()) { + return true; + } + return false; + } @Override - public boolean canInsert() { + public boolean canRetrieve(final Field field) { + if (field.getType() == Long.class) { + return true; + } + final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class); + if (field.getType() == decorators.targetEntity()) { + return true; + } return false; } @Override - public boolean canRetrieve(final Field field) { - return false; + public int generateQuerry(@NotNull final String tableName, @NotNull final Field field, @NotNull final StringBuilder querry, @NotNull final String name, @NotNull final int elemCount, + final QueryOptions options) throws Exception { + if (field.getType() == Long.class) { + querry.append(" "); + querry.append(tableName); + querry.append("."); + querry.append(name); + return elemCount + 1; + } + final ManyToOne decorators = field.getDeclaredAnnotation(ManyToOne.class); + if (field.getType() == decorators.targetEntity()) { + return DataAccess.generateSelectField(querry, field.getType(), options, elemCount); + } + return elemCount; } - + @Override - public int generateQuerry(@NotNull final String tableName, @NotNull final Field elem, @NotNull final StringBuilder querry, @NotNull final String name, @NotNull final int elemCount, - final QueryOptions options) { - querry.append(" "); - querry.append(tableName); - querry.append("."); - querry.append(name); - return 1; - } - - @Override - public int fillFromQuerry(final ResultSet rs, final Field elem, final Object data, final int count, final QueryOptions options) + public int fillFromQuerry(final ResultSet rs, final Field field, final Object data, final int count, final QueryOptions options) throws SQLException, IllegalArgumentException, IllegalAccessException { final Long foreignKey = rs.getLong(count); if (rs.wasNull()) { return 0; } - elem.set(data, foreignKey); + field.set(data, foreignKey); return 1; } - - @Override - public boolean canUpdate() { - return true; - } - + // TODO : refacto this table to manage a generic table with dynamic name to be serializable with the default system @Override - public void createTables(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List preActionList, final List postActionList, + public void createTables(final String tableName, final Field field, final StringBuilder mainTableBuilder, final List preActionList, final List postActionList, final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception { - DataFactory.createTablesSpecificType(tableName, elem, mainTableBuilder, preActionList, postActionList, createIfNotExist, createDrop, fieldId, Long.class); + DataFactory.createTablesSpecificType(tableName, field, mainTableBuilder, preActionList, postActionList, createIfNotExist, createDrop, fieldId, Long.class); } } diff --git a/src/org/kar/archidata/dataAccess/addOn/AddOnOneToMany.java b/src/org/kar/archidata/dataAccess/addOn/AddOnOneToMany.java new file mode 100644 index 0000000..a338f6a --- /dev/null +++ b/src/org/kar/archidata/dataAccess/addOn/AddOnOneToMany.java @@ -0,0 +1,129 @@ +package org.kar.archidata.dataAccess.addOn; + +import java.lang.reflect.Field; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +import org.kar.archidata.annotation.AnnotationTools; +import org.kar.archidata.dataAccess.DataAccessAddOn; +import org.kar.archidata.dataAccess.DataFactory; +import org.kar.archidata.dataAccess.QueryOptions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import jakarta.persistence.OneToMany; +import jakarta.validation.constraints.NotNull; + +public class AddOnOneToMany implements DataAccessAddOn { + static final Logger LOGGER = LoggerFactory.getLogger(AddOnManyToMany.class); + + /** + * Convert the list if external id in a string '-' separated + * @param ids List of value (null are removed) + * @return '-' string separated + */ + protected static String getStringOfIds(final List ids) { + final List tmp = new ArrayList<>(ids); + return tmp.stream().map(String::valueOf).collect(Collectors.joining("-")); + } + + /** + * extract a list of "-" separated element from a SQL input data. + * @param rs Result Set of the BDD + * @param iii Id in the result set + * @return The list of Long value + * @throws SQLException if an error is generated in the sql request. + */ + protected static List getListOfIds(final ResultSet rs, final int iii) throws SQLException { + final String trackString = rs.getString(iii); + if (rs.wasNull()) { + return null; + } + final List out = new ArrayList<>(); + final String[] elements = trackString.split("-"); + for (final String elem : elements) { + final Long tmp = Long.parseLong(elem); + out.add(tmp); + } + return out; + } + + @Override + public Class getAnnotationClass() { + return OneToMany.class; + } + + @Override + public String getSQLFieldType(final Field field) throws Exception { + final String fieldName = AnnotationTools.getFieldName(field); + try { + return DataFactory.convertTypeInSQL(Long.class, fieldName); + } catch (final Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return null; + } + + @Override + public boolean isCompatibleField(final Field field) { + final OneToMany decorators = field.getDeclaredAnnotation(OneToMany.class); + return decorators != null; + } + + @Override + public int insertData(final PreparedStatement ps, final Field field, final Object rootObject, int iii) throws SQLException, IllegalArgumentException, IllegalAccessException { + final Object data = field.get(rootObject); + if (data == null) { + ps.setNull(iii++, Types.BIGINT); + } else { + @SuppressWarnings("unchecked") + final String dataTmp = getStringOfIds((List) data); + ps.setString(iii++, dataTmp); + } + return iii++; + } + + @Override + public boolean canInsert(final Field field) { + return false; + } + + @Override + public boolean canRetrieve(final Field field) { + return false; + } + + @Override + public int generateQuerry(@NotNull final String tableName, @NotNull final Field field, @NotNull final StringBuilder querry, @NotNull final String name, @NotNull final int elemCount, + final QueryOptions options) { + querry.append(" "); + querry.append(tableName); + querry.append("."); + querry.append(name); + return 1; + } + + @Override + public int fillFromQuerry(final ResultSet rs, final Field field, final Object data, final int count, final QueryOptions options) + throws SQLException, IllegalArgumentException, IllegalAccessException { + final Long foreignKey = rs.getLong(count); + if (rs.wasNull()) { + return 0; + } + field.set(data, foreignKey); + return 1; + } + + // TODO : refacto this table to manage a generic table with dynamic name to be serializable with the default system + @Override + public void createTables(final String tableName, final Field field, final StringBuilder mainTableBuilder, final List preActionList, final List postActionList, + final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception { + DataFactory.createTablesSpecificType(tableName, field, mainTableBuilder, preActionList, postActionList, createIfNotExist, createDrop, fieldId, Long.class); + } +} diff --git a/src/org/kar/archidata/dataAccess/addOn/AddOnSQLTableExternalForeinKeyAsList.java b/src/org/kar/archidata/dataAccess/addOn/AddOnSQLTableExternalForeinKeyAsList.java index ed96168..0ae253b 100644 --- a/src/org/kar/archidata/dataAccess/addOn/AddOnSQLTableExternalForeinKeyAsList.java +++ b/src/org/kar/archidata/dataAccess/addOn/AddOnSQLTableExternalForeinKeyAsList.java @@ -40,8 +40,8 @@ public class AddOnSQLTableExternalForeinKeyAsList implements DataAccessAddOn { } @Override - public String getSQLFieldType(final Field elem) throws Exception { - final String fieldName = AnnotationTools.getFieldName(elem); + public String getSQLFieldType(final Field field) throws Exception { + final String fieldName = AnnotationTools.getFieldName(field); try { return DataFactory.convertTypeInSQL(String.class, fieldName); } catch (final Exception e) { @@ -52,13 +52,14 @@ public class AddOnSQLTableExternalForeinKeyAsList implements DataAccessAddOn { } @Override - public boolean isCompatibleField(final Field elem) { - final SQLTableExternalForeinKeyAsList decorators = elem.getDeclaredAnnotation(SQLTableExternalForeinKeyAsList.class); + public boolean isCompatibleField(final Field field) { + final SQLTableExternalForeinKeyAsList decorators = field.getDeclaredAnnotation(SQLTableExternalForeinKeyAsList.class); return decorators != null; } @Override - public int insertData(final PreparedStatement ps, final Object data, int iii) throws SQLException { + public int insertData(final PreparedStatement ps, final Field field, final Object rootObject, int iii) throws SQLException, IllegalArgumentException, IllegalAccessException { + final Object data = field.get(rootObject); if (data == null) { ps.setNull(iii++, Types.BIGINT); } else { @@ -70,7 +71,7 @@ public class AddOnSQLTableExternalForeinKeyAsList implements DataAccessAddOn { } @Override - public boolean canInsert() { + public boolean canInsert(final Field field) { return false; } @@ -80,7 +81,7 @@ public class AddOnSQLTableExternalForeinKeyAsList implements DataAccessAddOn { } @Override - public int generateQuerry(@NotNull final String tableName, @NotNull final Field elem, @NotNull final StringBuilder querry, @NotNull final String name, @NotNull final int elemCount, + public int generateQuerry(@NotNull final String tableName, @NotNull final Field field, @NotNull final StringBuilder querry, @NotNull final String name, @NotNull final int elemCount, final QueryOptions options) { querry.append(" "); querry.append(tableName); @@ -90,23 +91,18 @@ public class AddOnSQLTableExternalForeinKeyAsList implements DataAccessAddOn { } @Override - public int fillFromQuerry(final ResultSet rs, final Field elem, final Object data, final int count, final QueryOptions options) + public int fillFromQuerry(final ResultSet rs, final Field field, final Object data, final int count, final QueryOptions options) throws SQLException, IllegalArgumentException, IllegalAccessException { final List idList = DataAccess.getListOfIds(rs, count, SEPARATOR); - elem.set(data, idList); + field.set(data, idList); return 1; } @Override - public boolean canUpdate() { - return true; - } - - @Override - public void createTables(final String tableName, final Field elem, final StringBuilder mainTableBuilder, final List preActionList, final List postActionList, + public void createTables(final String tableName, final Field field, final StringBuilder mainTableBuilder, final List preActionList, final List postActionList, final boolean createIfNotExist, final boolean createDrop, final int fieldId) throws Exception { // TODO Auto-generated method stub - DataFactory.createTablesSpecificType(tableName, elem, mainTableBuilder, preActionList, postActionList, createIfNotExist, createDrop, fieldId, String.class); + DataFactory.createTablesSpecificType(tableName, field, mainTableBuilder, preActionList, postActionList, createIfNotExist, createDrop, fieldId, String.class); } } diff --git a/test/src/test/kar/archidata/TestManyToMany.java b/test/src/test/kar/archidata/TestManyToMany.java index 8bb98f9..99a8ea5 100644 --- a/test/src/test/kar/archidata/TestManyToMany.java +++ b/test/src/test/kar/archidata/TestManyToMany.java @@ -27,26 +27,26 @@ import test.kar.archidata.model.TypeManyToManyRoot; @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class TestManyToMany { final static private Logger LOGGER = LoggerFactory.getLogger(TestManyToMany.class); - + @BeforeAll public static void configureWebServer() throws Exception { ConfigBaseVariable.dbType = "sqlite"; ConfigBaseVariable.dbHost = "memory"; // for test we need to connect all time the DB ConfigBaseVariable.dbKeepConnected = "true"; - + // Connect the dataBase... final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); entry.connect(); } - + @AfterAll public static void removeDataBase() throws IOException { LOGGER.info("Remove the test db"); DBEntry.closeAllForceMode(); ConfigBaseVariable.clearAllValue(); } - + @Order(1) @Test public void testCreateTable() throws Exception { @@ -58,7 +58,7 @@ public class TestManyToMany { DataAccess.executeSimpleQuerry(elem, false); } } - + @Order(2) @Test public void testSimpleInsertAndRetieve() throws Exception { @@ -69,34 +69,34 @@ public class TestManyToMany { Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); Assertions.assertNull(insertedData.remote); - + // Try to retrieve all the data: final TypeManyToManyRoot retrieve = DataAccess.get(TypeManyToManyRoot.class, insertedData.id); - + Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); Assertions.assertEquals(insertedData.id, retrieve.id); Assertions.assertNotNull(retrieve.otherData); Assertions.assertEquals(insertedData.otherData, retrieve.otherData); Assertions.assertNull(retrieve.remote); - + DataAccess.delete(TypeManyToManyRoot.class, insertedData.id); } - + @Order(3) @Test public void testSimpleInsertAndRetieveZZZ() throws Exception { - + TypeManyToManyRemote remote = new TypeManyToManyRemote(); remote.data = "remote1"; final TypeManyToManyRemote insertedRemote1 = DataAccess.insert(remote); Assertions.assertEquals(insertedRemote1.data, remote.data); - + remote = new TypeManyToManyRemote(); remote.data = "remote2"; final TypeManyToManyRemote insertedRemote2 = DataAccess.insert(remote); Assertions.assertEquals(insertedRemote2.data, remote.data); - + final TypeManyToManyRoot test = new TypeManyToManyRoot(); test.otherData = "kjhlkjlkj"; final TypeManyToManyRoot insertedData = DataAccess.insert(test); @@ -104,23 +104,23 @@ public class TestManyToMany { Assertions.assertNotNull(insertedData.id); Assertions.assertTrue(insertedData.id >= 0); Assertions.assertNull(insertedData.remote); - + // Try to retrieve all the data: TypeManyToManyRoot retrieve = DataAccess.get(TypeManyToManyRoot.class, insertedData.id); - + Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); Assertions.assertEquals(insertedData.id, retrieve.id); Assertions.assertNotNull(retrieve.otherData); Assertions.assertEquals(insertedData.otherData, retrieve.otherData); Assertions.assertNull(retrieve.remote); - + // Add remote elements AddOnManyToMany.addLink(TypeManyToManyRoot.class, retrieve.id, "remote", insertedRemote1.id); AddOnManyToMany.addLink(TypeManyToManyRoot.class, retrieve.id, "remote", insertedRemote2.id); - - retrieve = DataAccess.get(TypeManyToManyRoot.class, insertedData.id); + retrieve = DataAccess.get(TypeManyToManyRoot.class, insertedData.id); + Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); Assertions.assertEquals(insertedData.id, retrieve.id); @@ -130,13 +130,13 @@ public class TestManyToMany { Assertions.assertEquals(retrieve.remote.size(), 2); Assertions.assertEquals(retrieve.remote.get(0), insertedRemote1.id); Assertions.assertEquals(retrieve.remote.get(1), insertedRemote2.id); - + // Remove an element int count = AddOnManyToMany.removeLink(TypeManyToManyRoot.class, retrieve.id, "remote", insertedRemote1.id); Assertions.assertEquals(1, count); - + retrieve = DataAccess.get(TypeManyToManyRoot.class, insertedData.id); - + Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); Assertions.assertEquals(insertedData.id, retrieve.id); @@ -145,21 +145,28 @@ public class TestManyToMany { Assertions.assertNotNull(retrieve.remote); Assertions.assertEquals(retrieve.remote.size(), 1); Assertions.assertEquals(retrieve.remote.get(0), insertedRemote2.id); - + // Remove the second element count = AddOnManyToMany.removeLink(TypeManyToManyRoot.class, retrieve.id, "remote", insertedRemote2.id); Assertions.assertEquals(1, count); - - retrieve = DataAccess.get(TypeManyToManyRoot.class, insertedData.id); + retrieve = DataAccess.get(TypeManyToManyRoot.class, insertedData.id); + Assertions.assertNotNull(retrieve); Assertions.assertNotNull(retrieve.id); Assertions.assertEquals(insertedData.id, retrieve.id); Assertions.assertNotNull(retrieve.otherData); Assertions.assertEquals(insertedData.otherData, retrieve.otherData); Assertions.assertNull(retrieve.remote); - + DataAccess.delete(TypeManyToManyRoot.class, insertedData.id); } + + /* + API TODO: + - Replace list (permet de les ordonnées) + - remove all links + - delete en cascade .... (compliqué...) + */ } \ No newline at end of file diff --git a/test/src/test/kar/archidata/TestManyToOne.java b/test/src/test/kar/archidata/TestManyToOne.java new file mode 100644 index 0000000..02408b8 --- /dev/null +++ b/test/src/test/kar/archidata/TestManyToOne.java @@ -0,0 +1,85 @@ +package test.kar.archidata; + +import java.io.IOException; +import java.util.List; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.kar.archidata.GlobalConfiguration; +import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.DataFactory; +import org.kar.archidata.db.DBEntry; +import org.kar.archidata.util.ConfigBaseVariable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import test.kar.archidata.model.TypeManyToOneRemote; +import test.kar.archidata.model.TypeManyToOneRoot; + +@ExtendWith(StepwiseExtension.class) +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class TestManyToOne { + final static private Logger LOGGER = LoggerFactory.getLogger(TestManyToOne.class); + + @BeforeAll + public static void configureWebServer() throws Exception { + ConfigBaseVariable.dbType = "sqlite"; + ConfigBaseVariable.dbHost = "memory"; + // for test we need to connect all time the DB + ConfigBaseVariable.dbKeepConnected = "true"; + + // Connect the dataBase... + final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); + entry.connect(); + } + + @AfterAll + public static void removeDataBase() throws IOException { + LOGGER.info("Remove the test db"); + DBEntry.closeAllForceMode(); + ConfigBaseVariable.clearAllValue(); + } + + @Order(1) + @Test + public void testCreateTable() throws Exception { + final List sqlCommand = DataFactory.createTable(TypeManyToOneRemote.class); + final List sqlCommand2 = DataFactory.createTable(TypeManyToOneRoot.class); + sqlCommand.addAll(sqlCommand2); + for (final String elem : sqlCommand) { + LOGGER.debug("request: '{}'", elem); + DataAccess.executeSimpleQuerry(elem, false); + } + } + + @Order(2) + @Test + public void testAddAlements() throws Exception { + TypeManyToOneRemote remote = new TypeManyToOneRemote(); + remote.data = "remote1"; + final TypeManyToOneRemote insertedRemote1 = DataAccess.insert(remote); + Assertions.assertEquals(insertedRemote1.data, remote.data); + + remote = new TypeManyToOneRemote(); + remote.data = "remote2"; + final TypeManyToOneRemote insertedRemote2 = DataAccess.insert(remote); + Assertions.assertEquals(insertedRemote2.data, remote.data); + + final TypeManyToOneRoot test = new TypeManyToOneRoot(); + test.otherData = "kjhlkjlkj"; + test.remoteId = insertedRemote2.id; + final TypeManyToOneRoot insertedData = DataAccess.insert(test); + Assertions.assertNotNull(insertedData); + Assertions.assertNotNull(insertedData.id); + Assertions.assertTrue(insertedData.id >= 0); + Assertions.assertEquals(test.otherData, insertedData.otherData); + Assertions.assertEquals(insertedData.remoteId, insertedRemote2.id); + + } +} \ No newline at end of file diff --git a/test/src/test/kar/archidata/TestOneToMany.java b/test/src/test/kar/archidata/TestOneToMany.java new file mode 100644 index 0000000..3fc458b --- /dev/null +++ b/test/src/test/kar/archidata/TestOneToMany.java @@ -0,0 +1,62 @@ +package test.kar.archidata; + +import java.io.IOException; +import java.util.List; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; +import org.junit.jupiter.api.extension.ExtendWith; +import org.kar.archidata.GlobalConfiguration; +import org.kar.archidata.dataAccess.DataAccess; +import org.kar.archidata.dataAccess.DataFactory; +import org.kar.archidata.db.DBEntry; +import org.kar.archidata.util.ConfigBaseVariable; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import test.kar.archidata.model.TypesTable; + +@ExtendWith(StepwiseExtension.class) +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class TestOneToMany { + final static private Logger LOGGER = LoggerFactory.getLogger(TestOneToMany.class); + + @BeforeAll + public static void configureWebServer() throws Exception { + ConfigBaseVariable.dbType = "sqlite"; + ConfigBaseVariable.dbHost = "memory"; + // for test we need to connect all time the DB + ConfigBaseVariable.dbKeepConnected = "true"; + + // Connect the dataBase... + final DBEntry entry = DBEntry.createInterface(GlobalConfiguration.dbConfig); + entry.connect(); + } + + @AfterAll + public static void removeDataBase() throws IOException { + LOGGER.info("Remove the test db"); + DBEntry.closeAllForceMode(); + ConfigBaseVariable.clearAllValue(); + } + + @Order(1) + @Test + public void testCreateTable() throws Exception { + final List sqlCommand = DataFactory.createTable(TypesTable.class); + for (final String elem : sqlCommand) { + LOGGER.debug("request: '{}'", elem); + DataAccess.executeSimpleQuerry(elem, false); + } + } + + @Order(2) + @Test + public void testPlop() throws Exception { + + } +} \ No newline at end of file diff --git a/test/src/test/kar/archidata/model/TypeManyToManyRootExpand.java b/test/src/test/kar/archidata/model/TypeManyToManyRootExpand.java new file mode 100644 index 0000000..a5d6f37 --- /dev/null +++ b/test/src/test/kar/archidata/model/TypeManyToManyRootExpand.java @@ -0,0 +1,20 @@ +package test.kar.archidata.model; + +import java.util.List; + +import jakarta.persistence.Column; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToMany; + +public class TypeManyToManyRootExpand { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(nullable = false, unique = true) + public Long id = null; + + @ManyToMany(fetch = FetchType.LAZY, targetEntity = TypeManyToManyRemote.class) + public List remote; +} diff --git a/test/src/test/kar/archidata/model/TypeManyToOneRemote.java b/test/src/test/kar/archidata/model/TypeManyToOneRemote.java new file mode 100644 index 0000000..a933bb0 --- /dev/null +++ b/test/src/test/kar/archidata/model/TypeManyToOneRemote.java @@ -0,0 +1,16 @@ +package test.kar.archidata.model; + +import jakarta.persistence.Column; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; + +public class TypeManyToOneRemote { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(nullable = false, unique = true) + public Long id = null; + + public String data; + +} \ No newline at end of file diff --git a/test/src/test/kar/archidata/model/TypeManyToOneRoot.java b/test/src/test/kar/archidata/model/TypeManyToOneRoot.java new file mode 100644 index 0000000..1203cbc --- /dev/null +++ b/test/src/test/kar/archidata/model/TypeManyToOneRoot.java @@ -0,0 +1,20 @@ +package test.kar.archidata.model; + +import jakarta.persistence.Column; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; + +public class TypeManyToOneRoot { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(nullable = false, unique = true) + public Long id = null; + + public String otherData; + + @ManyToOne(targetEntity = TypeManyToOneRemote.class) + @Column(nullable = false) + public Long remoteId; +} \ No newline at end of file diff --git a/test/src/test/kar/archidata/model/TypeManyToOneRootExpand.java b/test/src/test/kar/archidata/model/TypeManyToOneRootExpand.java new file mode 100644 index 0000000..9789531 --- /dev/null +++ b/test/src/test/kar/archidata/model/TypeManyToOneRootExpand.java @@ -0,0 +1,21 @@ +package test.kar.archidata.model; + +import jakarta.persistence.Column; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; + +public class TypeManyToOneRootExpand { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(nullable = false, unique = true) + public Long id = null; + + public String otherData; + + @ManyToOne(fetch = FetchType.LAZY, targetEntity = TypeManyToOneRemote.class) + @Column(name = "remoteId", nullable = false) + public TypeManyToOneRemote remote; +} \ No newline at end of file