Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1단계 - OneToMany (FetchType.EAGER) #114

Open
wants to merge 2 commits into
base: jshans40
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/main/java/jpa/EntityManagerImpl.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package jpa;

import persistence.sql.entity.EntityJoin;

import java.util.Collection;

public class EntityManagerImpl implements EntityManager {
private final EntityPersister entityPersister;
private final PersistenceContext persistenceContext;
Expand Down Expand Up @@ -31,9 +35,20 @@ public <T> T persist(T entity) {
T insertedEntity = entityPersister.insert(entity);
persistenceContext.add(entity);
persistenceContext.createDatabaseSnapshot(entity);

persistJoinEntity(entity);

return insertedEntity;
}

private <T> void persistJoinEntity(T entity) {
EntityJoin entityJoin = new EntityJoin(entity.getClass());
entityJoin.getEntityJoinInfos().forEach(entityJoinInfo -> {
Collection<?> entityJoinCollections = entityJoinInfo.getEntityJoinCollections(entity);
entityJoinCollections.forEach(this::persist);
});
}

@Override
public void merge(Object entity) {
if (persistenceContext.isDirty(entity)) {
Expand Down
32 changes: 19 additions & 13 deletions src/main/java/persistence/sql/ddl/CreateQueryBuilder.java
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
package persistence.sql.ddl;

import jakarta.persistence.Entity;
import jakarta.persistence.JoinTable;
import persistence.sql.Dialect;
import persistence.sql.entity.EntityJoin;
import persistence.sql.exception.ExceptionMessage;
import persistence.sql.exception.RequiredClassException;
import persistence.sql.model.TableName;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

public class CreateQueryBuilder implements QueryBuilder {
private static final String LEFT_PARENTHESIS = "(";
private static final String RIGHT_PARENTHESIS = ")";
private static final String SPACE = " ";

private final Class<?> clazz;
private final Dialect dialect;
private final List<String> createQueries = new ArrayList<>();

public CreateQueryBuilder(Class<?> clazz, Dialect dialect) {
if (clazz == null) {
Expand All @@ -30,14 +37,18 @@ public CreateQueryBuilder(Class<?> clazz, Dialect dialect) {
@Override
public String build() {
StringBuilder makeStringBuilder = new StringBuilder();
makeStringBuilder.append(createTableIfNotExistsStatement());
makeStringBuilder.append(generateColumnDefinitions());
return makeStringBuilder.toString();
makeStringBuilder.append(createTableIfNotExistsStatement(this.clazz));
makeStringBuilder.append(LEFT_PARENTHESIS);
makeStringBuilder.append(generateColumnDefinitions(this.clazz));
makeStringBuilder.append(RIGHT_PARENTHESIS);
createQueries.add(makeStringBuilder.toString());


return String.join(";", createQueries);
}

private String createTableIfNotExistsStatement() {
private String createTableIfNotExistsStatement(Class<?> clazz) {
TableName tableName = new TableName(clazz);

StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("CREATE TABLE IF NOT EXISTS");
stringBuilder.append(SPACE);
Expand All @@ -46,14 +57,9 @@ private String createTableIfNotExistsStatement() {
return stringBuilder.toString();
}

private String generateColumnDefinitions() {
DDLColumn ddlColumns = new DDLColumn(this.clazz.getDeclaredFields(), dialect);

StringBuilder columnDefinitionStringBuilder = new StringBuilder();
columnDefinitionStringBuilder.append(LEFT_PARENTHESIS);
columnDefinitionStringBuilder.append(ddlColumns.makeColumnsDDL());
columnDefinitionStringBuilder.append(RIGHT_PARENTHESIS);
return columnDefinitionStringBuilder.toString();
private String generateColumnDefinitions(Class<?> clazz) {
DDLColumn ddlColumns = new DDLColumn(clazz.getDeclaredFields(), dialect);
return ddlColumns.makeColumnsDDL();
}


Expand Down
6 changes: 2 additions & 4 deletions src/main/java/persistence/sql/ddl/DDLColumn.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package persistence.sql.ddl;

import jakarta.persistence.Column;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.Transient;
import jakarta.persistence.*;
import persistence.sql.Dialect;
import persistence.sql.exception.ExceptionMessage;
import persistence.sql.exception.RequiredFieldException;
Expand Down Expand Up @@ -42,6 +39,7 @@ public DDLColumn(Field[] fields, Dialect dialect) {
this.fields = new ArrayList<>(Arrays.asList(fields))
.stream()
.filter(field -> !field.isAnnotationPresent(Transient.class))
.filter(field -> !field.isAnnotationPresent(OneToMany.class))
.collect(Collectors.toList());
}

Expand Down
3 changes: 3 additions & 0 deletions src/main/java/persistence/sql/dml/InsertQuery.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package persistence.sql.dml;

import jakarta.persistence.GeneratedValue;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Transient;
import persistence.sql.exception.ExceptionMessage;
import persistence.sql.exception.RequiredObjectException;
Expand Down Expand Up @@ -42,6 +43,7 @@ private String columnsClause(Object object) {
return Arrays.stream(object.getClass().getDeclaredFields())
.filter(field -> !field.isAnnotationPresent(Transient.class))
.filter(field -> !field.isAnnotationPresent(GeneratedValue.class))
.filter(field -> !field.isAnnotationPresent(OneToMany.class))
.map(field -> new EntityColumnName(field).getValue())
.collect(Collectors.joining(", "));
}
Expand All @@ -50,6 +52,7 @@ private String valueClause(Object object) {
return Arrays.stream(object.getClass().getDeclaredFields())
.filter(field -> !field.isAnnotationPresent(Transient.class))
.filter(field -> !field.isAnnotationPresent(GeneratedValue.class))
.filter(field -> !field.isAnnotationPresent(OneToMany.class))
.map(field -> getValueInClause(object, field))
.collect(Collectors.joining(", "));
}
Expand Down
33 changes: 24 additions & 9 deletions src/main/java/persistence/sql/dml/SelectQuery.java
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package persistence.sql.dml;

import persistence.sql.entity.EntityJoin;
import persistence.sql.entity.EntityJoinInfo;
import persistence.sql.exception.ExceptionMessage;
import persistence.sql.exception.RequiredClassException;
import persistence.sql.model.EntityColumnNames;
import persistence.sql.model.TableName;
import persistence.sql.model.*;

public class SelectQuery {

Expand All @@ -26,7 +27,7 @@ public String findAll(Class<?> clazz) {

TableName tableName = new TableName(clazz);
EntityColumnNames entityColumnNames = new EntityColumnNames(clazz);
return String.format("SELECT %s FROM %s", entityColumnNames.getColumnNames(), tableName.getValue());
return String.format("SELECT %s FROM %s %s", entityColumnNames.getColumnNames(), tableName.getValue(), tableName.getAlias());
}


Expand All @@ -41,21 +42,35 @@ public String findById(Class<?> clazz, Object id) {

TableName tableName = new TableName(clazz);
EntityColumnNames entityColumnNames = new EntityColumnNames(clazz);
EntityJoin entityJoin = new EntityJoin(clazz);


StringBuilder findByIdQueryStringBuilder = new StringBuilder();
findByIdQueryStringBuilder.append("SELECT");
findByIdQueryStringBuilder.append(SPACE);
findByIdQueryStringBuilder.append(entityColumnNames.getColumnNames());

for (Class<?> joinClass : entityJoin.getJoinClasses()) {
EntityColumnNames joinEntityColumnNames = new EntityColumnNames(joinClass);
findByIdQueryStringBuilder.append(",");
findByIdQueryStringBuilder.append(SPACE);
findByIdQueryStringBuilder.append(joinEntityColumnNames.getColumnNames());
}

findByIdQueryStringBuilder.append(SPACE);
findByIdQueryStringBuilder.append("FROM");
findByIdQueryStringBuilder.append(SPACE);
findByIdQueryStringBuilder.append(tableName.getValue());
findByIdQueryStringBuilder.append(String.format("%s %s", tableName.getValue(), tableName.getAlias()));

if (entityJoin.isEntityJoin()) {
findByIdQueryStringBuilder.append(SPACE);
findByIdQueryStringBuilder.append(entityJoin.makeJoinTableQuery());
findByIdQueryStringBuilder.append(SPACE);
}

findByIdQueryStringBuilder.append(SPACE);
findByIdQueryStringBuilder.append("WHERE");
findByIdQueryStringBuilder.append(" ");
findByIdQueryStringBuilder.append("id=");
findByIdQueryStringBuilder.append(id);
WhereClause whereClause = new WhereClause("id", Operator.equals, id, tableName.getAlias());
findByIdQueryStringBuilder.append(whereClause.makeWhereQuery());
return findByIdQueryStringBuilder.toString();
}

}
5 changes: 5 additions & 0 deletions src/main/java/persistence/sql/entity/EntityFields.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,10 @@ public List<Field> getIdFields() {
.collect(Collectors.toList());
}

public String getIdFieldName() {
return getIdFields().get(0).getName();
}



}
75 changes: 75 additions & 0 deletions src/main/java/persistence/sql/entity/EntityJoin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package persistence.sql.entity;

import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToMany;
import persistence.sql.model.EntityId;
import persistence.sql.model.TableName;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class EntityJoin {

private final List<EntityJoinInfo> entityJoinInfos = new ArrayList<>();
private final EntityId entityId;

public EntityJoin(Class<?> clazz) {
addEntityJoinInfos(clazz);
this.entityId = new EntityId(clazz);
}

public void addEntityJoinInfos(Class<?> clazz) {
Arrays.stream(clazz.getDeclaredFields())
.filter(x -> x.isAnnotationPresent(OneToMany.class))
.forEach(field -> {
OneToMany oneToMany = field.getAnnotation(OneToMany.class);
JoinColumn joinColumn = field.getAnnotation(JoinColumn.class);

Type genericType = field.getGenericType();
Type[] types = ((ParameterizedType) genericType).getActualTypeArguments();
entityJoinInfos.add(
new EntityJoinInfo(
(Class<?>) types[0],
clazz,
new EntityId(clazz).getIdColumnName(),
oneToMany.fetch(),
joinColumn.name(),
field
)
);
});
}

public boolean isEntityJoin() {
return !entityJoinInfos.isEmpty();
}

public String makeJoinTableQuery() {
StringBuilder joinQueryBuilder = new StringBuilder();
entityJoinInfos.forEach(entityJoinInfo -> {
joinQueryBuilder.append("LEFT JOIN ");
joinQueryBuilder.append(entityJoinInfo.getJoinTableName());
joinQueryBuilder.append(" ON ");
joinQueryBuilder.append(new TableName(entityJoinInfo.getClazz()).getAlias());
joinQueryBuilder.append(".");
joinQueryBuilder.append(entityId.getIdColumnName());
joinQueryBuilder.append(" = ");
joinQueryBuilder.append(new TableName(entityJoinInfo.getJoinClazz()).getAlias());
joinQueryBuilder.append(".");
joinQueryBuilder.append(entityJoinInfo.getJoinColumnName());
});
return joinQueryBuilder.toString();
}

public List<Class<?>> getJoinClasses() {
return this.entityJoinInfos.stream().map(EntityJoinInfo::getJoinClazz).collect(Collectors.toList());
}

public List<EntityJoinInfo> getEntityJoinInfos() {
return entityJoinInfos;
}
}
60 changes: 60 additions & 0 deletions src/main/java/persistence/sql/entity/EntityJoinInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package persistence.sql.entity;

import jakarta.persistence.FetchType;
import persistence.sql.model.TableName;

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collection;

public class EntityJoinInfo {

private final String joinTableName;
private final String columnName;
private final String joinColumnName;
private final Class<?> joinClazz;
private final Class<?> clazz;
private final Field joinField;
private final FetchType fetchType;

public EntityJoinInfo(Class<?> joinClazz, Class<?> clazz, String columnName, FetchType fetchType, String joinColumnName, Field joinField) {
this.joinClazz = joinClazz;
TableName joinTableName = new TableName(joinClazz);
this.joinTableName = joinTableName.getValue();
this.columnName = columnName;
this.joinColumnName = joinColumnName;
this.clazz = clazz;
this.joinField = joinField;
this.fetchType = fetchType;
}


public String getJoinColumnName() {
return joinColumnName;
}

public String getJoinTableName() {
return joinTableName;
}

public Class<?> getJoinClazz() {
return this.joinClazz;
}

public Class<?> getClazz() {
return clazz;
}

public String getColumnName() {
return columnName;
}

public Collection<?> getEntityJoinCollections(Object entityObject) {
try {
this.joinField.setAccessible(true);
return (Collection<?>) this.joinField.get(entityObject);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
34 changes: 34 additions & 0 deletions src/main/java/persistence/sql/entity/Order.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package persistence.sql.entity;

import jakarta.persistence.*;

import java.util.ArrayList;
import java.util.List;

@Entity
@Table(name = "orders")
public class Order {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String orderNumber;

@OneToMany(fetch = FetchType.EAGER)
@JoinColumn(name = "order_id")
private List<OrderItem> orderItems;

public Order() {

}

public Order(String orderNumber) {
this.orderNumber = orderNumber;
this.orderItems = new ArrayList<>();
}

public List<OrderItem> getOrderItems() {
return orderItems;
}
}
Loading