OptaPlanner - 该实体从未添加到此ScoreDirector错误中

时间:2016-05-05 02:27:20

标签: optaplanner

我正在OptaPlanner中实现类似于NurseRoster的算法。我需要在drools中实施一项规则,检查Employee是否无法比contract中的天数工作更多天。由于我无法弄清楚如何在drools中进行此操作,因此我决定将其作为类中的方法编写,然后在drools中使用它来检查约束是否已被破坏。由于我在List课程中需要ShiftAssignments Employee,我需要使用@InverseRelationShadowVariable自动更新该列表,Employee已分配给{ {1}}。由于我的Shift现在必须是Employee,因此出现错误PlanningEntity。我认为该错误是由我的The entity was never added to this ScoreDirector实体引起的,该实体的ShiftAssignment @ValueRangeProvider可以在employees中使用。我认为这是因为ShiftScoreDirector.beforeEntityAdded从未被调用,因此错误。出于某种原因,当我从ScoreDirector.afterEntityAdded移除该范围提供程序并将其放在ShiftAssignment NurseRoster上时,它就有效了。

以下是代码:

员工:

@PlanningSolution

ShiftAssignment:

@InverseRelationShadowVariable(sourceVariableName = "employee")
public List<ShiftAssignment> getEmployeeAssignedToShiftAssignments() {
    return employeeAssignedToShiftAssignments;
}

NurseRoster:

@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();
}

这是我用来更新@ValueRangeProvider(id = "employeeRange") @PlanningEntityCollectionProperty public List<Employee> getEmployeeList() { return employeeList; }

的方法
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);
    }
}

我该如何解决此错误?

1 个答案:

答案 0 :(得分:1)

这肯定与解决方案克隆有关,当一个新的最佳解决方案&#34;被建造。

我实现自定义解决方案克隆时遇到了同样的错误。在我的项目中,我有多个计划实体类,并且它们都具有彼此的引用(单个值或列表)。因此,当解决方案克隆发生时,需要更新引用,以便它们可以指向克隆值。这是默认克隆过程没有问题的情况,因此使解决方案处于一致状态。它甚至可以正确地更新父计划实体中的计划实体实例列表(方法&#34; cloneCollectionsElementIfNeeded&#34;来自类&#34; FieldAccessingSolutionCloner&#34;来自OptaPlanner核心)。

只是展示我在规划实体类中所拥有的:

@PlanningEntity
public class ParentPlanningEntityClass{
    List<ChildPlanningEntityClass> childPlanningEntityClassList;
}

@PlanningEntity
public class ChildPlanningEntityClass{
    ParentPlanningEntityClass parentPlanningEntityClass;
}

首先,我没有更新任何引用,即使对于&#34; ChildPlanningEntityClass&#34;也得到了错误。然后我写了更新引用的代码。当谈到来自班级&#34; ChildPlanningEntityClass&#34;的计划实体实例时。此时一切都很好,因为他们指向克隆的对象。我在&#34; ParentPlanningEntityClass&#34;中做错了什么案例是我没有创建&#34; childPlanningEntityClassList&#34;使用&#34; new ArrayList();&#34;从头开始列表,但我刚刚更新了列表的元素(使用&#34; set&#34;方法)来指向&的克隆实例#34; ChildPlanningEntityClass&#34;类。在创建&#34; new ArrayList();&#34;时,填充元素以指向克隆对象并设置&#34; childPlanningEntityClassList&#34;列表一切都是一致的(用FULL_ASSERT测试)。

所以只需将它与我的问题联系起来就可以列出&#34; employeeAssignedToShiftAssignments&#34;不是从头开始用&#34; new ArrayList();&#34;而只是从列表中添加或删除元素。那么可能发生的事情(如果列表不是从头开始创建的)就是工作和新的最佳解决方案(克隆)将指向同一个列表,当工作解决方案将继续更改此列表时,它将破坏最佳方案。