2016-05-05 6 views
3

Ich implementiere einen ähnlichen Algorithmus wie den NurseRoster in OptaPlanner. Ich muss eine Regel in Drools implementieren, die überprüfen, ob die Employee nicht mehr Tage als die Anzahl der Tage in seiner contract arbeiten kann. Da ich nicht herausfinden konnte, wie man das in Drools macht, entschied ich mich, es als eine Methode in einer Klasse zu schreiben, und dann in Drools zu verwenden, um zu überprüfen, ob die Beschränkung gebrochen wurde. Da ich einen List von ShiftAssignments in der Employee Klasse brauchte, musste ich einen @InverseRelationShadowVariable verwenden, der diese Liste automatisch aktualisierte Employee wurde einem Shift zugewiesen. Da meine Employee jetzt eine PlanningEntity sein muss, erschien der Fehler The entity was never added to this ScoreDirector. Ich glaube, dass der Fehler durch meine ShiftAssignment Einheit verursacht wird, die eine @ValueRangeProvider von employees hat, die in dieser Shift arbeiten kann. Ich denke, das liegt an der Tatsache, dass ScoreDirector.beforeEntityAdded und ScoreDirector.afterEntityAdded nie aufgerufen wurden, daher der Fehler. Aus irgendeinem Grund, als ich diesen Bereichsprovider von ShiftAssignment entfernte und ihn auf NurseRoster setzte, was der @PlanningSolution ist, funktionierte es. HierOptaPlanner - Die Entität wurde nie zu diesem ScoreDirector-Fehler hinzugefügt.

ist der Code:

Mitarbeiter:

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

Und das ist die Methode, die ich zu aktualisieren verwenden, die 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); 
    } 
} 

Und die Regel, die ich benutze:

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 

Wie ich diesen Fehler beheben kann?

+0

Ist es nicht nur, weil die Mitarbeiter die 'getProblemFacts()' Methode Ihrer Lösung vermissen? Beachten Sie den Unterschied zwischen 'add()' und 'addAll()'. –

+0

Nein, ich glaube das ist nicht der Fall. Ich habe 'facts.addAll (employeeList);' hinzugefügt in der NurseRoster-Klasse. –

+0

Der gleiche Fehler, aber unter anderen Umständen tritt hier auf https://stackoverflow.com/questions/44193111/the-entity-was-never-added-to-this-scoredirector-exception-during-custom-cloning. –

Antwort

1

Dies hat definitiv etwas mit dem Klonen von Lösungen zu tun, wenn eine "neue beste Lösung" erstellt wird.

Ich habe den gleichen Fehler bei der Implementierung von benutzerdefinierten Lösungsklonen gefunden. In meinem Projekt habe ich mehrere Planungseinheitenklassen und alle haben Referenzen zueinander (entweder ein einzelner Wert oder eine Liste). Wenn also das Klonen von Lösungen stattfindet, müssen die Referenzen aktualisiert werden, damit sie auf die geklonten Werte zeigen können. Dies ist etwas, was der Standardklonierungsprozess ohne ein Problem durchführt und somit die Lösung in einem konsistenten Zustand belässt. Es aktualisiert sogar die Listen der Planungseinheiteninstanzen in den übergeordneten Planungselementen ordnungsgemäß (abgedeckt durch die Methode "cloneCollectionsElementIfNeeded" aus der Klasse "FieldAccessingSolutionCloner" aus dem OptaPlanner-Kern).

nur eine Demonstration, was ich habe, wenn es um die Planung Entitätsklassen kommt:

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

@PlanningEntity 
public class ChildPlanningEntityClass{ 
    ParentPlanningEntityClass parentPlanningEntityClass; 
} 

Zuerst habe ich keine der Referenzen zu aktualisieren und bekam den Fehler auch für „ChildPlanningEntityClass“. Dann habe ich den Code geschrieben, der die Referenzen aktualisiert. Bei den Instanzen der Planungseinheit, die aus der Klasse "ChildPlanningEntityClass" stammen, war an dieser Stelle alles in Ordnung, weil sie auf das geklonte Objekt zeigten.Was ich im "ParentPlanningEntityClass" -Fall falsch gemacht habe, war, dass ich die "childPlanningEntityClassList" -Liste nicht von Grund auf mit "new ArrayList();" erstellt habe, sondern stattdessen die Elemente der Liste aktualisiert habe (mit der "set" -Methode) um auf die geklonten Instanzen der Klasse "ChildPlanningEntityClass" zu zeigen. Beim Erstellen einer "new ArrayList();" -Füllung der Elemente, um auf die geklonten Objekte zu zeigen und die "childPlanningEntityClassList" -Liste zu setzen, war alles konsistent (getestet mit FULL_ASSERT).

Also nur verbinden es zu meinem Problem möglicherweise die Liste "employeeAssignedToShiftAssignments" ist nicht von Grund auf mit "new ArrayList();" und Elemente werden nur hinzugefügt oder aus der Liste entfernt. Was also passieren könnte (wenn die Liste nicht von Grund auf neu erstellt wird), ist, dass sowohl die funktionierende als auch die neue beste Lösung (der Klon) auf die gleiche Liste zeigen und wenn die Arbeitslösung diese Liste weiter verändern würde, würde sie die beste Lösung.

Verwandte Themen