How can I use the entitymanager metamodel to find fields with certain properties - jpa

I wonder if it is possible to use the entitymanager metamodel to scan over loaded entities to identify fields with certain properties during a test. For example I want to see if any fields are defined as strings with a "max length of 1" to report them as possible "Char" type columns.
val model = em.metamodel
model.entities.forEach { entity ->
entity.attributes.filter { !it.isCollection }.filter { it.javaType.isAssignableFrom(String::class.java) }
.forEach { attribute ->
attribute // <- TODO here be dragons
}
}"

Related

JPA Specification Select returns all columns instead of specific

I am using JPA Specification , need to select specific columns only.
This is the code:
Specification<Item> spec = (root, query, builder) -> {
query.select(root.get("Id"));
Predicate predicate = builder.equal(root.get("Id"), "12345");
return predicate;
};
In log I see that all columns from Item Entity are selected from database.
Is it a bug?
 usage:
interface:
public interface Repo extends PagingAndSortingRepository<Item,String>, JpaSpecificationExecutor<Item> {
}
call:
repo.findAll(spec );
JpaSpecificationExecutor is specifically defined to return the entity type. I suspect it is ignoring the .select(root.get("Id")).
Normally you would use Specifications if you have an extremely dynamic set of conditions you are querying by. If you have just a few parameters you need to search by, I would use a derived query, or a named query.
public interface Repo extends PagingAndSortingRepository<Item,String>, JpaSpecificationExecutor<Item> {
#Query("Select i.id from Item i where name=:name")
Long getIdforName(String name);
}

SpringBatch JpaPagingItemReader SortOrder

I am using SpringBatch version 3.0.7, Hibernate 4.3.11, and H2 database. When using the JpaPagingItemReader, does the JPQL require a unique sort order? I see that it is required for the JdbcPagingItemReader (see BATCH-2465).
In a Step I am using a JpaPagingItemReader to load entities from the database and then write them to a flat file. I expect the flat file to contain unique entities sorted in the order specified by the JPQL. If I set the page size to something small, like 1, and then provide a JPQL statement that sorts entities with a non unique key, I am seeing the same entity repeat multiple times in the output file. If I sort by a unique key, there are no "duplicates". If I set the page size >= total number of entities, so there is only 1 page, there are no "duplicates".
Empirically it would seem that the JpaPagingItemReader requires the JPQL to have a unique sort key.
Having a look at the implementation of JpaPagingItemReader, you'll find the method doReadPage():
#Override
#SuppressWarnings("unchecked")
protected void doReadPage() {
EntityTransaction tx = null;
if (transacted) {
tx = entityManager.getTransaction();
tx.begin();
entityManager.flush();
entityManager.clear();
}//end if
Query query = createQuery().setFirstResult(getPage() * getPageSize()).setMaxResults(getPageSize());
if (parameterValues != null) {
for (Map.Entry<String, Object> me : parameterValues.entrySet()) {
query.setParameter(me.getKey(), me.getValue());
}
}
if (results == null) {
results = new CopyOnWriteArrayList<T>();
}
else {
results.clear();
}
if (!transacted) {
List<T> queryResult = query.getResultList();
for (T entity : queryResult) {
entityManager.detach(entity);
results.add(entity);
}//end if
} else {
results.addAll(query.getResultList());
tx.commit();
}//end if
}
As you can see, for every page that is read, an new query is created for every Page. Therefore, it must be ensured that your query returns always the same amount of elements in the exact same order, and hence, it needs a 'unique sort key'. Otherwise you will have duplicates and missing entries (there will be a missing entry for every duplicate, since the total number of rows will be identical).

Is it possible to map a list of fields in a Play/Scala form

Given some object that has the ability to query its fields, is it possible to iterate over the fields to generate a list of mappings and to use the list of mappings to create a form?
For example:
class SomeModel ...
val model = new SomeModel
val mappings = model.fields { f =>
f.fieldName -> text // Just use String/text mappings to simplify the example
}
// Assuming 'of' is the correct mapping to use, What should be
// specified for <?1>, <?2> and <?3>
val form = Form(
of( <?1> , <?2> ) {
<?3>
}
)
Background:
I need to build a basic crud interface for our data model which consists of a 100+ tables, some with up to a 100 columns. Refactoring the data model is not an option since this crud interface is just one of many other users of the data. We generate the model classes so it is possible to also generate the form classes but I am hoping that I can get around the 18 / 22 field limit by using a list of fields instead.

Entity Framework TPH - Additional WHERE clause only for one subtype

Suppose I have a class Parent, with two subclasses, AChild and BChild. I have these mapped to a single table using Entity Framework 5.0.0 on .NET 4.5, using TPH.
public abstract class Parent {
public string Type { get; set; } // Column with this name in DB is discriminator.
public string Status { get; set; }
}
public class AChild : Parent {
// Other stuff.
}
public class BChild : Parent {
// Other stuff.
}
The code to configure the mapping:
class ParentConfiguration : EntityTypeConfiguration<Parent> {
Map((EntityMappingConfiguration<AChild> mapping) => mapping
.Requires("Type")
.HasValue("A"));
Map((EntityMappingConfiguration<BChild> mapping) => mapping
.Requires("Type")
.HasValue("B"));
}
I have a need to run a query that returns both AChild and BChild objects. However, it needs to filter ONLY the AChild rows by a second column, which in this example I will call Status.
Ideally I would want to do the following:
public IList<Parent> RunQuery() {
IQueryable<Parent> query =
this.context.Set<Parent>()
.Where((Parent parent) => !parent.Type.Equals("A") || parent.Status.Equals("Foo"))
.OrderBy((Parent parent) => parent.Number);
return query.ToList();
}
This doesn't work. It insisted on looking for a "Type1" column instead of just letting both the discriminator and a "Type" property be mapped to the same "Type" column.
I know of the "OfType" extension method that can be used to completely filter down to one type, but that's too broad a brush in this case.
I could possibly run multiple queries and combine the results, but the actual system I'm building is doing paging, so if I need to pull back 10 rows, it gets messy (and inefficient) to query since I'll either end up pulling back too many rows, or not pull back enough and have to run extra queries.
Does anyone have any other thoughts?
There are few problems. First of all you cannot have discriminator mapped as a property. That is the reason why it is looking for Type1 column - your Type property results in second column because the first one is already mapped to .NET types of your classes. The only way to filter derived types is through OfType.
The query you want to build will be probably quite complex because you need to query for all Bs and concatenate them with result of query for filtered As. It will most probably not allow you to concatenate instances of Bs with As so you will have to convert them back to parent type.

Entity Framework and Sorting

I'm trying to sort a list of entities using a GridView in ASP.NET, but I can't seem to get it working following examples. I have a property called Name on my entity, and I'm trying to sort by a specified column if given, or the Name column if the sortExpression is empty.
public static List<Product> GetProducts(int startRowIndex, int maximumRows, string sortExpression) {
using(var context = new ShopEntities()) {
var products = context.Products;
products.OrderBy("it."+(string.IsNullOrEmpty(sortExpression) ? "Name" : sortExpression))
.Skip(startRowIndex)
.Take(maximumRows);
return products.ToList();
}
}
I can't get it to sort though. The only other option seems to be doing a switch on the property name for every property in the entity and using a lambda.
OrderBy doesn't mutate the expression. It returns a new expression, which your code ignores. Change your code to:
products = products.OrderBy("it."+ //...