Synchronize two lucene documents mapped for the same table (entity) - lucene

Consider two identical Java entities (PersonM1, PersonM2) mapped for the same table (PERSON) with the same attributes defined as:
#Entity
#Table(name = "PERSON")
#Indexed
public class PersonM1 {
#Id
#DocumentId
private long id;
#Field
#Column
private String name;
//setters, gettes, ...
}
#Entity
#Table(name = "PERSON")
#Indexed
public class PersonM2 {
#Id
#DocumentId
private long id;
#Field
#Column
private String name;
//setters, gettes, ...
}
Is there a way to update PersonM2 indexes when we update a PersonM1 object?
If The object PersonM1 is updated, changes are persisted on the database, but not in PersonM2 index directory, so PersonM2 indexes won't be correct in this case.
Shall I do it manually (update PersonM1 when PersonM2 is updated)?
Note: Java inheritance trick is not relevant!

There is no way currently, as the identity of the indexed type is represented directly the the class instance of the model. This will change in Hibernate Search 5, so in that version you might have a "clean" solution for such a scenario but I don't know yet if we will expose an API for this, and how this would look like. You'll probably have to provide your custom implementation of "entity identity".

Related

How to construct Spring Data repository query two Parameters with IN and same list?

This is my Entity:
#Data
#Entity
#IdClass(EtlJobExecutionTriggersId.class)
#Table(name = "ETL_JOB_EXEC_TRIGGERS")
public class EtlJobExecutionTriggers {
#Id private Long jobExecIdUs;
#Id private Long jobExecIdDs;
private LocalDate cobDate;
}
And here is the Composite Primary Key Class:
#Data
#NoArgsConstructor
#AllArgsConstructor
#Embeddable
#EqualsAndHashCode
public class EtlJobExecutionTriggersId implements Serializable {
private Long jobExecIdUs;
private Long jobExecIdDs;
}
And here is my Spring Repo:
public interface EtlJobExecTriggersRepo extends JpaRepository<EtlJobExecutionTriggers, EtlJobExecutionTriggersId> {
String SQL_ = "select o from EtlJobExecutionTriggers o where o.jobExecIdDs in (:ids) or o.jobExecIdUs in (:ids) order by o.jobExecIdUs, o.jobExecIdDs";
#Query(EtlJobExecTriggersRepo.SQL_)
List<EtlJobExecutionTriggers> findAllByJobExecIdDsInAndJobExecIdUsInSQL(#Param("ids") List<Long> jobExecIdList);
}
The #Query works as expected, but I would like not to write any SQL and instead express the same Query using only Spring Data repository query.
I have tried the following (and other variants)
List<EtlJobExecutionTriggers> findAllByJobExecIdDsInAndJobExecIdUsInOrderByJobExecIdUsJobExecIdDs(List<Long> jobExecIdDsList)
But i keep getting errors when Booting. The above interface method yields the following exception for the OrderBy part:
org.springframework.data.mapping.PropertyReferenceException: No property jobExecIdDs found for type Long! Traversed path: EtlJobExecutionTriggers.jobExecIdUs.
So what am I doing wrong here? or is it not possible to express this particular query via Spring Data Repo query?
As I have written in my comment I fixed the Order by issue, but I am still unable to make it work with only one method parameter (List jobExecIdList)
When I make it with two (List jobExecIdDsList, List jobExecIdUsList)
Like this:
List<EtlJobExecutionTriggers> findAllByJobExecIdDsInAndJobExecIdUsInOrderByJobExecIdUsAscJobExecIdDsAsc(List<Long> jobExecIdDsList, List<Long> jobExecIdUsList);
it actually works but I can't get to work with only one list, as in the #Query("....") method
I think using your own custom id generator conflicts with Spring Data Repository query.
// You shoud have two parameters in your method as below.
List findAllByJobExecIdDsInAndJobExecIdUsInOrderByJobExecIdUsJobExecIdDs(List jobExecIdDsList,List jobExecIdUsList);

Best way to set transient attribute on entity instance after Metadata.create

I'm currently setting the result of a jpql query on a transient attribute of several instances of entities attached with composition using BeforeDetachEntityListener.
Since I'm also using Metadata.create to create them, I would like to be able to do the same operation after creating them. What's the best way to handle the situation?
You can set values at object creation time with #PostConstruct
public class MyEntity extends StandardEntity {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "USER_ID")
protected User creator;
#PostConstruct
protected void init() {
setCreator(AppBeans.get(UserSessionSource.class).getUserSession().getUser());
}
}
More information about how to initialize data in entities can be found in the docs at 5.8.3.1 Entity Fields Initialization and 5.8.3 Assigning Initial Values

Recommended strategy to use Value Objects for ID's in Spring Data

Using Value Objects can have a lot of advantages, especially when it comes to the type strictness of it. Using a PersonKey to use a Person (where the PersonKey really is a wrapped Long) is a lot safer than just using a Long or String as-is. I was wondering what the recommended strategy to deal with this in Spring Data is, however. Setting up the Repository is of course a matter of for example using
public interface PersonRepository CrudRepository<Person, PersonKey> {
}
but I was wondering what the best way to make the PersonKey class would be, having it map easily. Is there a better option than using an EmbeddedKey?
There is two annotations to do it : IdClass or EmbeddedId. I would recommend to use EmbeddedId because you don't have to repeat all of your attributes of your id class into your entity class.
Let's say you use EmbeddedId. It would looks like this :
#Embeddable
public class PersonKey {
private Long id;
}
#Entity
public class Person {
#EmbeddedId
private PersonKey personKey;
}
And you will access to your id like this :
select p.personKey.id from Person p
But with IdClass, your Person class would look like this :
#Entity
#IdClass(Person.key)
public class Person {
#Id
private Long id;
}
And you will access like this :
select p.id from Person p

Hibernate inheritance without table for basic entity

I've never used inheritance in hibernate and I don't know which strategy should I use (or even do I really need to use strategy). I have three tables with the same interface (the same columns) and I want to create three entities with basic interface for them so it will look like this:
#Entity
+ Basic
+ #Entity
#Table(name="TABLE_1")
Table1
+ #Entity
#Table(name="TABLE_2")
Table2
+ #Entity
#Table(name="TABLE_3")
Table3
As you see I don't want to use table for basic entity. If it is possible to do this kind of inheritance, how to do it? Maybe I don't need 'hibernate' inheritance and I should use normal inheritance?
In application it is used like this:
Somewhere in configuration we store information which entity to use (Table1, Table12 or Table3)
Choosen entity is used in our queries (some writen in HQL, some in Criteria) so each query should know which entity to use.
EDIT
What's more each entity can be used as attribute of some entities and we wan't to know which table should be used. For example:
#Entity
#Table(name="USER")
class User {
#Id
private Integer id;
#ManyToOne
#JoinColumn(name = "SOME_ID", referencedColumnName = "ID", nullable = false)
private Basic basicEntity; // how to use proper strategy using some configuration value (eg. class static attribute or configuration value stored in db?)
}
I think this is recommended way of achieving your goal:
#MappedSuperclass
public abstract class BaseEntity {
public static final int SHARED_PAREMETER = 2;
#Column(name = "modified", columnDefinition = "TIMESTAMP DEFAULT NOW()")
protected Date modified;
//... other fields, getters and setters
}
#Entity
#Table(name = "TABLE_1")
public class Table1 {
#Id
private Integer id;
#ManyToOne
#JoinColumn(name = "SOME_ID", referencedColumnName = "ID", nullable = false)
private Table2 table2;
}
#Entity
#Table(name = "TABLE_2")
public class Table2 {
#Id
private Integer id;
}
In this case, we will have only two tables but both would have fields from BaseEntity. You can't, though, make a relation in Entity to an abstract class but in processing you're fully entitled to do something like this:
public void process(BaseEntity entity){
// processing..
}

How to fetch data from two tables(one-to-many relations) using Hibernate Createcriteria

How to fetch data from two tables based upon User id ?
*****************Role Class***********************
#Entity
#Table(name = "IUC_CON_USER_ROLE_MAP")
public class Role {
#Id
#Column(name="F_ROLE_MAP_ID")
int rolemap;
#Column(name="F_ROLE_ID")
int roleid;
#OneToMany(mappedBy="role",fetch=FetchType.EAGER)
Set<User> F_USER_ID;
*********************User class*******************
#Entity
#Table(name = "IUC_CON_USER")
public class User implements Serializable {
#Id
#Column(name = "F_USER_ID")
private int id;
#Column(name = "F_USER_NAME")
private String name;
#Column(name = "F_USER_PWD")
private String pwd;
#ManyToOne
#JoinColumn(name="F_USER_ID",insertable=false,updatable=false)
private Role role;
----------setter and getter for properties
}
External edit:
Criteria creation code:
DetachedCriteria uCrit = DetachedCriteria.forClass(User.class, "user");
uCrit.add(Restrictions.eq("user.id", 5));
uCrit.setProjection(Projections.property("user.id"));
DetachedCriteria criteria = DetachedCriteria.forClass(Role.class, "role");
criteria.add(Property.forName("role.F_USER_ID").in(uCrit));
List lt1 = criteria.getExecutableCriteria(getSession()).list();
use createAlias
criteria.createAlias("propertiy_of_main_entity", "aliastName");
For me this fetches entities asociated with root entity via some entity property name;
in your case something like
createAlias("F_USER_ID", "roleUsers");
should do.
Anyway why ins't your field name following commong naming doctrine for Java? WHY_IS_IT_UPPERCASED_WITH_DASHES_LIKE_CONSTANTS_?
All in all everything is explained in Hibernate documentation. If alias won't work, than fetch associations like in examples from Hibernate documentation under link I provided.
You can use below series of statements to fetch User along with the Role:
int userId = 1;
Criteria criteria = session.createCriteria(User.class);
criteria.setFetchMode("role", FetchMode.JOIN);
criteria.add(Restrictions.eq("id", userId));
User user = (User) criteria.uniqueResult();
The default fetching strategy of Hibernate is to fetch the associations lazily, which you need to override at runtime in code, if you want the associations (here the Role) to be fetched along with User. The third statement is doing this overriding by seting the fetch mode to JOIN. This statement FetchMode.JOIN overrides the default behavior, so that Role will be fetched along with the User.