Eclipselink : Operation not supported: [instantiateForUnitOfWorkValueHolder] - eclipselink

I get the following error when I try to access Lazy loaded #oneToMany relationship attribute in a method present in Entity.
Error:
Caused by: Exception [EclipseLink-7097] (Eclipse Persistence Services - 2.6.3.v20160428-59c81c5): org.eclipse.persistence.exceptions.ValidationException
Exception Description: Operation not supported: [instantiateForUnitOfWorkValueHolder].
at org.eclipse.persistence.exceptions.ValidationException.operationNotSupported(ValidationException.java:1496)
at org.eclipse.persistence.internal.indirection.ProtectedValueHolder.instantiateForUnitOfWorkValueHolder(ProtectedValueHolder.java:61)
at org.eclipse.persistence.internal.indirection.UnitOfWorkValueHolder.instantiateImpl(UnitOfWorkValueHolder.java:160)
at org.eclipse.persistence.internal.indirection.UnitOfWorkValueHolder.instantiate(UnitOfWorkValueHolder.java:234)
at org.eclipse.persistence.internal.indirection.DatabaseValueHolder.getValue(DatabaseValueHolder.java:89)
at org.eclipse.persistence.indirection.IndirectList.buildDelegate(IndirectList.java:271)
at org.eclipse.persistence.indirection.IndirectList.getDelegate(IndirectList.java:455)
at org.eclipse.persistence.indirection.IndirectList$1.<init>(IndirectList.java:597)
at org.eclipse.persistence.indirection.IndirectList.listIterator(IndirectList.java:596)
at org.eclipse.persistence.indirection.IndirectList.iterator(IndirectList.java:555)
at com.order.modelGroupBase.getStatus(GroupBase.java:205)
Entity:
#Entity
#Table(name="GROUP")
#Customizer(GroupBaseCustomizer.class)
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#ClassExtractor(GroupClassExtractor.class)
#InstantiationCopyPolicy
#Cacheable
#Cache( alwaysRefresh=true,
refreshOnlyIfNewer=true,
expiry=300000,
coordinationType = CacheCoordinationType.SEND_NEW_OBJECTS_WITH_CHANGES)
public class GroupBase {
#OneToMany(cascade=CascadeType.ALL, mappedBy="groupBase", targetEntity=Groups.class)
#PrivateOwned
private List groups = new ArrayList<>();
public OrderGroupStatus getStatus() {
//error is at this line when I try to iterate..
for (Iterator itr = getGroups().iterator(); itr.hasNext();) {
Groups relationship = (Groups) itr.next();
//some operation..
}
}
}
I've looked upon in eclipselink forum but they don't address this issue explicitly and some links say it's related to weaving.But in my application I haven't enabled weaving at all and I also don't intend to do.
This code works fine on Eclipselink 2.3.2 without JPA. Now I'm using Eclipselink 2.6.3 with JPA 2.0 and IBM Websphere 8.5.5.8.
Note: This issue occurs randomly not every time and also when ever a new object is created is what I have observed.

After many hit and trails and correcting my lazy loading settings, I've found out that using different fetchType on same entity in other entities can cause this issue in SHARED_CACHE mode.
#OneToMany(cascade=CascadeType.ALL, mappedBy="groupBase", targetEntity=Groups.class)
#PrivateOwned
private List groups = new ArrayList<>();
By default #OneToMany is lazily fetched but in another entity for the same entity 'Groups' I had configured fetchType as EAGER.
When I made both fetch types to LAZY this error stopped occurring.

Related

The entity was never added to this scoreDirector exception during custom cloning

I'm trying to implement custom cloning in my solution, i followed the instructions as in the documentation, and i encountered a roadblock in the form of this exception : The entity was never added to this ScoreDirector. Maybe that specific instance is not in the return values of the PlanningSolution's entity members. I know that this is not true because before the custom cloning, this exception wasn't thrown.
My planningClone method is setup like this :
#Override
public Solution planningClone() {
Solution clonedSolution = new Solution();
clonedSolution.id = id;
clonedSolution.code = code;
clonedSolution.score = score;
clonedSolution.field1 = field1;
clonedSolution.field2 = field2;
...............
clonedSolution.fieldN = fieldN;
List<PlanningEntity1> clonedPlanningEntity1List= new ArrayList<PlanningEntity1>(planningEntity1List.size());
List<PlanningEntity2> clonedPlanningEntity2List= new ArrayList<PlanningEntity2>(planningEntity1List.size());
for (PlanningEntity1 planningEntity: planningEntity1List) {
clonedPlanningEntity1List.add(planningEntity.clone());
}
for (PlanningEntity2 planningEntity: planningEntity2List) {
clonedPlanningEntity1List.add(planningEntity.clone());
}
clonedSolution.planningEntity1List = clonedPlanningEntity1List;
clonedSolution.planningEntity2List = clonedPlanningEntity2List;
return clonedSolution;
{
The clone method for my planning entities is implemented through the Java interface Cloneable:
protected PlanningEntity clone() {
try {
return (PlanningEntity) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
Just to be sure, i checked every entity instance and their collections to make sure my cloning was working correctly, and it in fact is.
What step am i missing here?
If there is one planning entity pointing to another planning entity from a different class or maybe pointing to a list, than the cloning process needs to take care of the references for those planning entities so they point to the cloned objects.This is something that the default cloning process is doing without a problem, and thus leaving the solution in a consistent state. It even updates the Lists of planning entity instances in the parent planning entities correctly (covered by the method "cloneCollectionsElementIfNeeded" from the class "FieldAccessingSolutionCloner" from the OptaPlanner core).
So for example if we have the next two planning entity classes
#PlanningEntity
public class ParentPlanningEntityClass{
List<ChildPlanningEntityClass> childPlanningEntityClassList;
}
#PlanningEntity
public class ChildPlanningEntityClass{
ParentPlanningEntityClass parentPlanningEntityClass;
}
The "parentPlanningEntityClass" variable needs to be set to point to the cloned object. When it comes to the list "childPlanningEntityClassList" it first needs to be created from scratch with "new ArrayList();" so that both the working and new best solution (the one that is currently getting cloned) don't point to the same list. At the end the newly created list needs to be filled with the cloned objects.

In-memory H2 database, insert not working in SpringBootTest

I have a SpringBootApplicationWhich I wish to test.
Below are the details about my files
application.properties
PRODUCT_DATABASE_PASSWORD=
PRODUCT_DATABASE_USERNAME=sa
PRODUCT_DATABASE_CONNECTION_URL=jdbc:h2:file:./target/db/testdb
PRODUCT_DATABASE_DRIVER=org.h2.Driver
RED_SHIFT_DATABASE_PASSWORD=
RED_SHIFT_DATABASE_USERNAME=sa
RED_SHIFT_DATABASE_CONNECTION_URL=jdbc:h2:file:./target/db/testdb
RED_SHIFT_DATABASE_DRIVER=org.h2.Driver
spring.datasource.platform=h2
ConfigurationClass
#SpringBootConfiguration
#SpringBootApplication
#Import({ProductDataAccessConfig.class, RedShiftDataAccessConfig.class})
public class TestConfig {
}
Main Test Class
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(classes = {TestConfig.class,ConfigFileApplicationContextInitializer.class}, webEnvironment = SpringBootTest.WebEnvironment.NONE)
public class MainTest {
#Autowired(required = true)
#Qualifier("dataSourceRedShift")
private DataSource dataSource;
#Test
public void testHourlyBlock() throws Exception {
insertDataIntoDb(); //data sucessfully inserted
SpringApplication.run(Application.class, new String[]{}); //No data found
}
}
Data Access In Application.class;
try (Connection conn = dataSourceRedShift.getConnection();
Statement stmt = conn.createStatement() {
//access inserted data
}
Please Help!
PS for the spring boot application the test beans are being picked so bean instantiation definitely not a problem. I think I am missing some properties.
I do not use hibernate in my application and data goes off even within the same application context (child context). i.e. I run a spring boot application which reads that data inserted earlier
Problem solved.
removing spring.datasource.platform=h2 from the application.properties.
Made my h2 data persists.
But I still wish to know how is h2 starting automatically?

OptaPlanner - The entity was never added to this ScoreDirector error

I am implementing an algorithm similar to the NurseRoster one in OptaPlanner. I need to implement a rule in drools that check if the Employee cannot work more days than the number of days in his contract. Since i couldn't figure out how to make this in drools, i decided to write it as a method in a class, and then use it in drools to check if the constraint has been broken. Since i needed a List of ShiftAssignments in the Employee class, i needed to use an #InverseRelationShadowVariable that updated that list automatically an Employee got assigned to a Shift. Since my Employee now has to be a PlanningEntity, the error The entity was never added to this ScoreDirector appeared. I believe the error is caused by my ShiftAssignment entity, which has a #ValueRangeProvider of employees that can work in that Shift. I think this is due to the fact that ScoreDirector.beforeEntityAdded and ScoreDirector.afterEntityAdded were never called, hence the error. For some reason when i removed that range provider from ShiftAssignment and put it on NurseRoster which is the #PlanningSolution, it worked.
Here is the code:
Employee:
#InverseRelationShadowVariable(sourceVariableName = "employee")
public List<ShiftAssignment> getEmployeeAssignedToShiftAssignments() {
return employeeAssignedToShiftAssignments;
}
ShiftAssignment:
#PlanningVariable(valueRangeProviderRefs = {
"employeeRange" }, strengthComparatorClass = EmployeeStrengthComparator.class,nullable = true)
public Employee getEmployee() {
return employee;
}
// the value range for this planning entity
#ValueRangeProvider(id = "employeeRange")
public List<Employee> getPossibleEmployees() {
return getShift().getEmployeesThatCanWorkThisShift();
}
NurseRoster:
#ValueRangeProvider(id = "employeeRange")
#PlanningEntityCollectionProperty
public List<Employee> getEmployeeList() {
return employeeList;
}
And this is the method i use to update that listOfEmployeesThatCanWorkThisShift:
public static void checkIfAnEmployeeCanBelongInGivenShiftAssignmentValueRange(NurseRoster nurseRoster) {
List<Shift> shiftList = nurseRoster.getShiftList();
List<Employee> employeeList = nurseRoster.getEmployeeList();
for (Shift shift : shiftList) {
List<Employee> employeesThatCanWorkThisShift = new ArrayList<>();
String shiftDate = shift.getShiftDate().getDateString();
ShiftTypeDefinition shiftTypeDefinitionForShift = shift.getShiftType().getShiftTypeDefinition();
for (Employee employee : employeeList) {
AgentDailySettings agentDailySetting = SearchThroughSolution.findAgentDailySetting(employee, shiftDate);
List<ShiftTypeDefinition> shiftTypeDefinitions = agentDailySetting.getShiftTypeDefinitions();
if (shiftTypeDefinitions.contains(shiftTypeDefinitionForShift)) {
employeesThatCanWorkThisShift.add(employee);
}
}
shift.setEmployeesThatCanWorkThisShift(employeesThatCanWorkThisShift);
}
}
And the rule that i use:
rule "maxDaysInPeriod"
when
$shiftAssignment : ShiftAssignment(employee != null)
then
int differentDaysInPeriod = MethodsUsedInScoreCalculation.employeeMaxDaysPerPeriod($shiftAssignment.getEmployee());
int maxDaysInPeriod = $shiftAssignment.getEmployee().getAgentPeriodSettings().getMaxDaysInPeriod();
if(differentDaysInPeriod > maxDaysInPeriod)
{
scoreHolder.addHardConstraintMatch(kcontext, differentDaysInPeriod - maxDaysInPeriod);
}
end
How can i fix this error?
This has definitely something to do with the solution cloning that is happening when a "new best solution" is created.
I encountered the same error when i implemented custom solution cloning. In my project i have multiple planning entity classes and all of them have references to each other (either a single value or a List). So when solution cloning is happening the references need to be updated so they can point to the cloned values. This is something that the default cloning process is doing without a problem, and thus leaving the solution in a consistent state. It even updates the Lists of planning entity instances in the parent planning entities correctly (covered by the method "cloneCollectionsElementIfNeeded" from the class "FieldAccessingSolutionCloner" from the OptaPlanner core).
Just a demonstration what i have when it comes to the planning entity classes:
#PlanningEntity
public class ParentPlanningEntityClass{
List<ChildPlanningEntityClass> childPlanningEntityClassList;
}
#PlanningEntity
public class ChildPlanningEntityClass{
ParentPlanningEntityClass parentPlanningEntityClass;
}
At first i did not update any of the references and got the error even for "ChildPlanningEntityClass". Then i have written the code that updates the references. When it comes to the planning entity instances that were coming from the class "ChildPlanningEntityClass" everything was okay at this point because they were pointing to the cloned object. What i did wrong in the "ParentPlanningEntityClass" case was that i did not create the "childPlanningEntityClassList" list from scratch with "new ArrayList();", but instead i just updated the elements of the list (using the "set" method) to point at the cloned instances of the "ChildPlanningEntityClass" class. When creating a "new ArrayList();", filling the elements to point to the cloned objects and setting the "childPlanningEntityClassList" list everything was consistent (tested with FULL_ASSERT).
So just connecting it to my issue maybe the list "employeeAssignedToShiftAssignments" is not created from scratch with "new ArrayList();" and elements instead just get added or removed from the list. So what could happen (if the list is not created from scratch) here is that both the working and the new best solution (the clone) will point to the same list and when the working solution would continue to change this list it would corrupt the best solution.

NHibernate not persisting changes to my object

My ASP.NET MVC 4 project is using NHibernate (behind repositories) and Castle Windsor, using the AutoTx and NHibernate Facilities. I've followed the guide written by haf and my I can create and read objects.
My PersistenceInstaller looks like this
public class PersistenceInstaller : IWindsorInstaller
{
public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
{
container.AddFacility<AutoTxFacility>();
container.Register(Component.For<INHibernateInstaller>().ImplementedBy<NHibernateInstaller>().LifeStyle.Singleton);
container.AddFacility<NHibernateFacility>(
f => f.DefaultLifeStyle = DefaultSessionLifeStyleOption.SessionPerWebRequest);
}
}
The NHibernateInstaller is straight from the NHib Facility Quickstart.
I am using ISessionManager in my base repository...
protected ISession Session
{
get
{
return _sessionManager.OpenSession();
}
}
public virtual T Commit(T entity)
{
Session.SaveOrUpdate(entity);
return entity;
}
Finally, my application code which is causing the problem:
[HttpPost]
[ValidateAntiForgeryToken]
[Transaction]
public ActionResult Maintain(PrescriberMaintainViewModel viewModel)
{
if (ModelState.IsValid)
{
var prescriber = UserRepository.GetPrescriber(User.Identity.Name);
//var prescriber = new Prescriber { DateJoined = DateTime.Today, Username = "Test" };
prescriber.SecurityQuestion = viewModel.SecurityQuestion;
prescriber.SecurityAnswer = viewModel.SecurityAnswer;
prescriber.EmailAddress = viewModel.Email;
prescriber.FirstName = viewModel.FirstName;
prescriber.LastName = viewModel.LastName;
prescriber.Address = new Address
{
Address1 = viewModel.AddressLine1,
Address2 = viewModel.AddressLine2,
Address3 = viewModel.AddressLine3,
Suburb = viewModel.Suburb,
State = viewModel.State,
Postcode = viewModel.Postcode,
Country = string.Empty
};
prescriber.MobileNumber = viewModel.MobileNumber;
prescriber.PhoneNumber = viewModel.PhoneNumber;
prescriber.DateOfBirth = viewModel.DateOfBirth;
prescriber.AHPRANumber = viewModel.AhpraNumber;
prescriber.ClinicName = viewModel.ClinicName;
prescriber.ClinicWebUrl = viewModel.ClinicWebUrl;
prescriber.Qualifications = viewModel.Qualifications;
prescriber.JobTitle = viewModel.JobTitle;
UserRepository.Commit(prescriber);
}
return View(viewModel);
}
The above code will save a new prescriber (tested by uncommenting out the commented out line etc).
I am using NHProf and have confirmed that no sql is sent to the database for the Update. I can see the read being performed but that's it.
It seems to me that NHibernate doesn't recognise the entity as being changed and therefore does not generate the sql. Or possibly the transaction isn't being committed?
I've been scouring the webs for a few hours now trying to work this one out and as a last act of desperation have posted on SO. Any ideas? :)
Oh and in NHProf I see three Sessions (1 for the GetPrescriber call from the repo, one I assume for the update (with no sql) - and one for some action in my actionfilter on the base class). I also get an alert about the use of implicit transactions. This confuses me because I thought I was doing everything I needed to get an transaction - using AutoTx and the Transaction attribute. I also expected there to be only 1 session per webrequest, as per my Windsor config.
UPDATE: It seems, after spending the day reading through the source for NHibernateFacility and AutoTx Facility for automatic transactions, that AutoTx is not setting the Interceptors on my implementation of INHibernateInstaller. It seems this means whenever SessionManager calls OpenSession it is calling the default version with no parameter, rather than the one that accepts an Interceptor. Internally AutoTxFacility registers TransactionInterceptor with windsor, so that it can be added the Interceptor on my INHibernateInstaller concrete, by windsor making use of the AutoTx's TransactionalComponentInspector
AutoTxFacility source on github
To me it looks like creating sessions for every call to the repository. A session should span the whole business operation. It should be opened at the beginning and committed and disposed at the end.
There are other strange things in this code.
Commit is a completely different concept than SaveOrUpdate.
And you don't need to tell NH to store changes anyway. You don't need to call session.Save for objects that are already in the session. They are stored anyway. You only need to call session.Save when you add new objects.
Make sure that you use a transaction for the whole business operation.
There is one most likely "unintended" part in the code snippet above. And proven by observation made by NHProf
Oh and in NHProf I see three Sessions (1 for the GetPrescriber call
from the repo, one I assume for the update (with no sql) - and one for
some action in my actionfilter on the base class).
Calling the OpenSession() is triggering creation of a new session instances.
protected ISession Session
{
get { return _sessionManager.OpenSession(); }
}
So, whenever the code is accessing the Session property, behind is new session instance created (again and again). One session for get, one for udpate, one for filter...
As we can see here, the session returned by SessionManager.OpenSession() must be used for the whole scope (Unit of work, web request...)
http://docs.castleproject.org/Windsor.NHibernate-Facility.ashx
The syntaxh which we need, si to create one session (when firstly accessed) and reuse it until enf of scope (then later correctly close it, commit or rollback transaction...). Anyhow, first thing right now is to change the Session property this way:
ISession _session;
protected ISession Session
{
get
{
if (_session == null)
{
_session = sessionFactory.OpenSession();
}
return _session;
}
}
After spending a full day yesterday searching through the AutoTx and NHibernate facilities on github and getting nowhere, I started a clean project in an attempt to replicate the problem. Unfortunately for the replication, everything worked! I ran Update-Package on my source and brought down new version of Castle.Transactions and I was running correctly. I did make a small adjustment to my own code. That was to remove the UserRepository.Commit line.
I did not need to modify how I opened sessions. That was taken care of by the SessionManager instance. With the update to Castle.Transactions, the Transaction attribute is being recognised and a transaction is being created (as evidenced by no more alert in NHProf).

Refreshing an entity throws an NHibernate.UnresolvableObjectException

The entities and mappings I'm talking about in this question can be found here :)
Here is the context:
I have a parent view-model which helps to manage some entities, and which has its own session.
From this VM, I open another view-model (with its own session too), do some changements to the entity (add and/or remove children), and when I validate the changements, I commit the session and warns the first view-model to refresh the display:
public void Validate()
{
using (var tx = Session.BeginTransaction())
{
try
{
SelectedTeam.ClearRoster();
foreach (var teamPlayer in TeamPlayers)
SelectedTeam.AddPlayer(teamPlayer);
teamsRepository.SaveOrUpdate(SelectedTeam);
tx.Commit();
}
catch (Exception ex)
{
tx.Rollback();
}
finally
{
if (tx.WasCommitted)
ServiceLocator.Current.GetInstance<Mediator>().NotifyColleagues(MediatorMessages.DisplayEntityInfos, SelectedTeam.Id);
}
}
}
Here is the faulted method of the parent VM:
public void RefreshEntitiesListAndDisplayEntityInfos(int selectedEntityId)
{
TEntity entity = entitiesRepository.Load(selectedEntityId);
Session.Refresh(entity);
//...
}
The exception is thrown at the Refresh line:
NHibernate.UnresolvableObjectException
And the message is:
No row with the given identifier exists[Emidee.CommonEntities.PlayerInTeam#3
I can open and change the entity multiple times, but it seems that the exception is thrown when I delete a children, then add another one, and finally delete another one.
After some readings on the web, it seems that's because when I refresh the entity, and because I changed the HasMany relationship (because I have deleted a player for example), NH tries to reload the deleted row.
I've tried to add a NotFound.Ignore statement on the HasMany in my mappings, I've tried to force a new query to the DB instead of a Load, but I still get this exception.
Does someone know how I could fix that?
Thanks in advance
Mike
This is a known behavior when refreshing objects with modified collections.
To force reload, change your method to do session.Evict with the entity as a parameter. This is the code we use in our base model class:
public T ReGet<T>(T entity) where T : IEntity
{
var id = entity.Id;
Session.Evict(entity);
return Session.Get<T>(id);
}
Well, I've just spotted the problem.
To update the players list of the team, I used to clear the list, and add the new players, before updating the entity.
Now, I update the list by removing and adding only the players who have been moved by the user, and I don't have any problems at all now.
That's weird. I don't know what was wrong before, but as least that works now.