mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-10-23 21:15:52 +00:00
#866 - Fix RawSql mapping such that it automatically maps foreign key columns
This commit is contained in:
@@ -363,8 +363,15 @@ class CQueryBuilder {
|
||||
RawSql.ColumnMapping.Column column = it.next();
|
||||
String propertyName = column.getPropertyName();
|
||||
if (!RawSqlBuilder.IGNORE_COLUMN.equals(propertyName)) {
|
||||
|
||||
ElPropertyValue el = descriptor.getElGetValue(propertyName);
|
||||
if (el == null && propertyName.endsWith("Id")) {
|
||||
// try default naming convention for foreign key columns
|
||||
String foreignIdPath = assocOneIdPath(propertyName);
|
||||
el = descriptor.getElGetValue(foreignIdPath);
|
||||
if (el != null) {
|
||||
propertyName = foreignIdPath;
|
||||
}
|
||||
}
|
||||
if (el == null) {
|
||||
throw new PersistenceException("Property [" + propertyName + "] not found on " + descriptor.getFullName());
|
||||
} else {
|
||||
@@ -404,6 +411,13 @@ class CQueryBuilder {
|
||||
return new SqlTreeBuilder(request, predicates, detail, rawNoId).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a path for a foreign key property using the default naming convention.
|
||||
*/
|
||||
private String assocOneIdPath(String propertyName) {
|
||||
return propertyName.substring(0, propertyName.length() - 2) + ".id";
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the SQL response with row limiting (when not an update statement).
|
||||
*/
|
||||
|
||||
@@ -35,7 +35,13 @@ class CQueryPlanRawSql extends CQueryPlan {
|
||||
|
||||
// set the resultSet index positions for the property expressions
|
||||
for (int i = 0; i < chain.size(); i++) {
|
||||
indexPositions[i] = 1 + columnMapping.getIndexPosition(chain.get(i));
|
||||
String logicalPropertyPath = chain.get(i);
|
||||
int mappedPosition = columnMapping.getIndexPosition(logicalPropertyPath);
|
||||
if (mappedPosition == -1 && logicalPropertyPath.endsWith(".id")) {
|
||||
// try a automatically mapped foreign key
|
||||
mappedPosition = columnMapping.getIndexPosition(foreignKeyPath(logicalPropertyPath));
|
||||
}
|
||||
indexPositions[i] = 1 + mappedPosition;
|
||||
}
|
||||
|
||||
// check and handle the case where a discriminator column for
|
||||
@@ -51,4 +57,12 @@ class CQueryPlanRawSql extends CQueryPlan {
|
||||
|
||||
return indexPositions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path for a foreign key column that was automatically mapped.
|
||||
*/
|
||||
private String foreignKeyPath(String logicalPropertyPath) {
|
||||
// trim the .id and replace with Id ... to reverse the auto fk mapping earlier
|
||||
return logicalPropertyPath.substring(0, logicalPropertyPath.length() - 3) + "Id";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.avaje.ebean.BaseTestCase;
|
||||
import com.avaje.ebean.Ebean;
|
||||
import com.avaje.ebean.RawSql;
|
||||
import com.avaje.ebean.RawSqlBuilder;
|
||||
import com.avaje.tests.model.basic.Customer;
|
||||
import com.avaje.tests.model.basic.EBasic;
|
||||
import com.avaje.tests.model.basic.Order;
|
||||
import com.avaje.tests.model.basic.OrderDetail;
|
||||
@@ -13,7 +14,7 @@ import org.junit.Test;
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
import static org.assertj.core.api.StrictAssertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
@@ -54,6 +55,72 @@ public class TestRawSqlMasterDetail extends BaseTestCase {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testForeignKeyColumn() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
// billing_address_id fk column is automatically
|
||||
// mapped to the logical path: billingAddress.id
|
||||
|
||||
String rs = "select c.id, c.name, c.billing_address_id, c.updtime "+
|
||||
"from o_customer c " +
|
||||
"order by c.id";
|
||||
|
||||
RawSql rawSql = RawSqlBuilder.parse(rs).create();
|
||||
|
||||
List<Customer> customers = Ebean.find(Customer.class)
|
||||
.setRawSql(rawSql)
|
||||
.findList();
|
||||
|
||||
assertThat(customers).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleNestedColumn() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
|
||||
String rs = "select c.id, c.name, c.billing_address_id, ba.line_1, ba.city, c.updtime "+
|
||||
"from o_customer c " +
|
||||
" left join o_address ba on ba.id = c.billing_address_id "+
|
||||
"order by c.id";
|
||||
|
||||
RawSql rawSql = RawSqlBuilder.parse(rs)
|
||||
.tableAliasMapping("ba", "billingAddress")
|
||||
.create();
|
||||
|
||||
List<Customer> customers = Ebean.find(Customer.class)
|
||||
.setRawSql(rawSql)
|
||||
.findList();
|
||||
|
||||
assertThat(customers).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleJoinColumn() {
|
||||
|
||||
ResetBasicData.reset();
|
||||
|
||||
String rs = "select c.id, c.name, c.billing_address_id, ba.line_1, ba.city, c.updtime, sa.id, sa.line_1, sa.city "+
|
||||
"from o_customer c " +
|
||||
" left join o_address ba on ba.id = c.billing_address_id "+
|
||||
" left join o_address sa on sa.id = c.shipping_address_id "+
|
||||
"order by c.id";
|
||||
|
||||
RawSql rawSql = RawSqlBuilder.parse(rs)
|
||||
.tableAliasMapping("ba", "billingAddress")
|
||||
.tableAliasMapping("sa", "shippingAddress")
|
||||
.create();
|
||||
|
||||
List<Customer> customers = Ebean.find(Customer.class)
|
||||
.setRawSql(rawSql)
|
||||
.findList();
|
||||
|
||||
assertThat(customers).isNotEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithTableAliasMapping() {
|
||||
|
||||
|
||||
Reference in New Issue
Block a user