We are using spring data mongo repositories to store/retrieve documents. Following is the Java structure of classes we have got:
Abstract class A -> Concrete Classes B and C
We are writing the documents using save() method. when a document is saved, "_class" variable is saved which stores the classPath.
Now, when we try and query the data, we are getting the documents of both B and C classes. Following is the example:
public List<B> findByName (String name);
When we call this method, the list (surprisingly) contains the objects of C as well. It may be because B and C have one property which has same name.
My question is, if we want to restrict the result to specific class, is it possible using Mongo repository?
We tried with findBy_Class, findByClass but it threw an exception saying it was not able to find "class" member in "B".
Shouldn't the return type (e.g. List<B>) help filtering the objects? Any ideas?
Thanks in advance.
On the query object there's a "restrict" method which returns only objects of a given type.
http://docs.spring.io/spring-data/mongodb/docs/current/api/index.html?org/springframework/data/mongodb/core/MongoOperations.html
I suppose you could do something like that :
query.restrict(B.class).findByName(...)
Related
We use Eclipselink-2.6 with wildfly-8 server in a JavaEE7 application.
we have three JPA entities A, B, and C.
B and C extend A.
In order to change the type of an object "myObjectId" A to B, we try to:
1- Change the dtype value from "a" to "b" in Table "A" for the instance "myObjectId" using the criteria query.
2- Create a new row in the table "B" in the database for the same id "myObjectId" also with a criteria query.
3- Clearing the cache by evictAll as well Entitymanger using clear functions.
After, when I tried to find all data of type B, the object "myObjectId" came in the list but with type A!
After restarting wildfly server and call findAll, therefore, the data came with type B!
why myObjectId didn't change its type even if the first and the second level cache was cleared!?
See https://wiki.eclipse.org/EclipseLink/Examples/JPA/Caching
Essentially EclipseLink maps the JPA cache eviction call to its own invalidation logic, which seems to be keeping a reference to the object using a soft reference so that object identity is maintained. This prevents A1->B1->A1' from happening on cycles with lazy relationships.
Try calling ((JpaEntityManager)em.getDelegate()).getServerSession().getIdentityMapAccessor().initializeAllIdentityMaps() as suggested in the doc and then reading in the changed class.
When using JPA createQuery(), I found that we can use both class name and entity name to get the DB data.
This is by class name
em.createQuery("from com.model.Stuff s",
Stuff.class).getResultList();
And this is from entity name
em.createQuery("from Stuff s",
Stuff.class).getResultList();
This is in orm.xml
<entity class="com.model.Stuff" name="Stuff">
No matter which one i use, JPA can get the specific class that i am using from the orm.xml or from the annotation that i put in class.
So why i have to put Stuff.class in the parameter?
Because it can only put at most two parameters in createQuery(), What if i have to select two Class to do some join?
i cannot do this
em.createQuery("from Stuff s, Thing t where s.id = t.stuff_id", Stuff.class, Thing.class).getResultList();
Is
em.createQuery("from Stuff s",
Stuff.class).getResultList();
equal
em.createQuery("select s from Stuff s",
Stuff.class).getResultList();
Thanks to give me some help.
Stuff.class goes into the parameter to determine what type of query result object. A query can be infinitely complicated with dozens of nested types, but it must return one type of object in the end.
Then you must create a third Java type that will be result of join. Think about it, what type SHOULD the result be after a join?
As far as I know, yes
Is it possible to have an entity such as
#Entity
class Aggreate {
B b;
C c;
D d;
}
where aggreate itself is not stored in a seperate table, but B C D are? Aggregate will be queryable and will cascade operations to its parts. I will use such a class to manage B, C, D without exposing their methods to everyone.
Maybe you could consider using construction of an aggregate result class as described in Result Classes (Constructor Expressions)
JPA supports wrapping JPQL query results with instances of custom result classes. This is mainly useful for queries with multiple SELECT expressions, where custom result objects can provide an object oriented alternative to representing results as Object[] elements.
Any class with a compatible constructor can be used as a result class. It could be a JPA managed class (e.g. an entity class) but it could also be a lightweight 'transfer' class that is only used for collecting and processing query results.
It sounds like those are not entities per se, to be sure a knowledge of the domain is needed.
If they aren't needed as entities maybe the #Embeddable can help.
I'm using Spring JPA with hibernate and have an entity with a lot of properties, let's say it has five; as illustrated below:
#Entity
#Table
public class MyEntity{
Object properties1;
Object properties2;
Object properties3;
Object properties4;
Object properties5;
}
Spring provides a very nice feature; it generates JPQL query based on method name in the repository. For example:
List<MyEntity> findByProperties3(Object properties3);
In my situation, users have an html form to search for a MyEntity. This html form has five fields respectively which correspond to the five properties on the MyEntity class. User also can leave any field empty so that the search will include all values of this property in the query.
I have idea of how to implement that but it would break away from the Spring convenience methods and need a lot of coding. My idea is to create a method on the repository interface for all possibilities: user leaving all field empty, filling one field, two fields, etc; up to five fields. Unfortunately, that means that there would be:
possibilities. How can I avoid this path? Ideally, I would create just one method:
List<MyEntity> findByProperties1andProperties2andProperties3andProperties4andProperties5(Object p1,Object p2,Object p3,Object p4,Object p5)
But, if some of the pXs are null, then Spring JPA will explicitly find MyEntitys with propertiesX equal to null, as opposed to all possible values of, say, 1, 2, 3, 4, 5 and null.
===========EDIT===============
I am still hoping to get an answer from someone about a Spring JPA solution, but I've used javax.persistence.criteria.CriteriaBuilder in the mean time for my solution.
(as advised re-posting this question here... originally posted in msdn forum)
I am striving to write a "generic" routine for some simple CRUD operations using EF/Linq to Entities. I'm working in ASP.NET (C# or VB).
I have looked at:
Getting a reference to a dynamically selected table with "GetObjectByKey" (But I don't want anything from cache. I want data from database. Seems like not what this function is intended for).
CRM Dynamic Entities (here you can pass a tablename string to query) looked like the approach I am looking for but I don't get the idea that this CRM effort is necessarily staying current (?) and/or has much assurance for the future??
I looked at various ways of drilling thru Namespaces/Objects to get to where I could pass a TableName parameter into the oft used query syntax var query = (from c in context.C_Contacts select c); (for example) where somehow I could swap out the "C_Contacts" TEntity depending on which table I want to work with. But not finding a way to do this ??
Slightly over-simplyfing, I just want to be able to pass a tablename parameter and in some cases some associated fieldnames and values (perhaps in a generic object?) to my routine and then let that routine dynamically plug into LINQ to Entity data context/model and do some standard "select all" operations for parameter table or do a delete to parameter table based on a generic record id. I'm trying to avoid calling the various different automatically generated L2E methods based on tablename etc...instead just trying to drill into the data context and ultimately the L2E query syntax for dynamically passed table/field names.
Has anyone found any successful/efficient approaches for doing this? Any ideas, links, examples?
The DbContext object has a generic Set() method. This will give you
from c in context.Set<Contact>() select c
Here's method when starting from a string:
public void Test()
{
dynamic entity = null;
Type type = Type.GetType("Contract");
entity = Activator.CreateInstance(type);
ProcessType(entity);
}
public void ProcessType<TEntity>(TEntity instance)
where TEntity : class
{
var result =
from item in this.Set<TEntity>()
select item;
//do stuff with the result
//passing back to the caller can get more complicated
//but passing it on will be fine ...
}