Home Forum Nuclos Entwicklung Makros und Regeln BusinessObject is not in a modified state

Ansicht von 7 Beiträgen - 1 bis 7 (von insgesamt 7)
  • Autor
    Beiträge
  • #8067
    Josef Hopfgartner
    Teilnehmer

    Hallo Forum!
    Ich habe im Wiki das Beispiel zur InsertFinalRule gefunden und es für meine Anwendung herangezogen.
    Jedoch mache ich hier etwas falsch.

    Fehler:

    Caused by: org.nuclos.api.exception.BusinessException: BusinessObject is not in a modified state and cannot be updated.
    at org.nuclos.server.nbo.BusinessObjectServiceProvider.update(BusinessObjectServiceProvider.java:119)
    at org.nuclos.api.provider.BusinessObjectProvider.update(BusinessObjectProvider.java:81)
    at at.netzagentur.versuch.BuchungAusFahrzeugkosten_IFR.insertFinal(BuchungAusFahrzeugkosten_IFR.java:26)
    at org.nuclos.server.eventsupport.ejb3.EventSupportFacadeBean.executeInsertSupportEvent(EventSupportFacadeBean.java:1003)
    … 96 more

    Das Attribut BuchungId ist in diesem Fall NULL.
    Das Businessobjekt wird also geändert.
    Daher verstehe ich den Fehler nicht…

    package at.netzagentur.versuch;

    import org.nuclos.api.rule.InsertFinalRule;
    import org.nuclos.api.context.InsertContext;
    import org.nuclos.api.annotation.Rule;
    import org.nuclos.api.exception.BusinessException;
    import org.nuclos.api.provider.BusinessObjectProvider;

    @Rule(name="BuchungAusFahrzeugkosten_IFR", description="BuchungAusFahrzeugkosten")
    public class BuchungAusFahrzeugkosten_IFR implements InsertFinalRule {

    public void insertFinal(InsertContext context) throws BusinessException {
    Fahrzeugkosten fahrzKo = context.getBusinessObject(Fahrzeugkosten.class);

    if (fahrzKo.getBuchung() == null ) {
    java.lang.Long kto=40008172L;
    Buchung bu = new Buchung();
    bu.setKontoId(kto);
    bu.setDatum(fahrzKo.getDatum());
    bu.setReferenz(fahrzKo.getPartner() + bu.getDatum().toString());
    bu.setReferenznummer(fahrzKo.getId().intValue());
    bu.setSoll(fahrzKo.getSummegroovy());
    BusinessObjectProvider.insert(bu);
    fahrzKo.setBuchungId(bu.getId());
    }
    BusinessObjectProvider.update(fahrzKo);
    }
    }

    #8068
    Ramin Goettlich
    Teilnehmer

    Hallo,

    das BO ist nicht geändert, siehe auch http://support.nuclos.de/browse/NUCLOS-3895

    Mit einer kleinen Änderung funktionierts:

    Long id = BusinessObjectProvider.insert(bu);
    fahrzKo.setBuchungId(id);

    Das BusinessObjectProvider.update(fahrzKo); sollte auch in den IF-Teil, sonst knallts auch sobald fahrzKo.getBuchung() != null.

    Grüsse,
    nuclosian

    #8071
    Josef Hopfgartner
    Teilnehmer

    Danke für den Hinweis. Der Fehler blieb jedoch.
    Ich arbeite mit Nuclos 4.3.2Beta.

    Irgendwie will das BO „Fahrzeugkosten“ einfach nicht den Status auf „isUpdate“ geändert bekommen…

    Ich habe die Regel entsprechend umgeschrieben.
    Eigentlich war die Änderung bzgl. der update-Methode ja lediglich die Einführung einer zusätzlichen Long „id“.
    Zuvor hatte ich halt statt dessen den Funktionsaufruf mit getId() im Einsatz.

    Hier der abgeänderte Code, der immer noch den selben Fehler wirft:

    public void insertFinal(InsertContext context) throws BusinessException {
    Fahrzeugkosten fahrzKo = context.getBusinessObject(Fahrzeugkosten.class);

    if (fahrzKo.getBuchung() == null ) {
    java.lang.Long kto=40008172L;
    Buchung bu = new Buchung();
    bu.setKontoId(kto);
    bu.setDatum(fahrzKo.getDatum());
    bu.setReferenz(fahrzKo.getPartner() + bu.getDatum().toString());
    bu.setReferenznummer(fahrzKo.getId().intValue());
    bu.setSoll(fahrzKo.getSummegroovy());
    Long id = BusinessObjectProvider.insert(bu);
    System.out.println("DEBUG bu.id " + id);
    fahrzKo.setBuchungId(id);
    BusinessObjectProvider.update(fahrzKo);
    }
    }

    DEBUG bu.id 40009215

    #8072
    Ramin Goettlich
    Teilnehmer

    Sorry, das geht so tatsächlich nicht. In einer insert/insertFinal-Regel befindet sich das Objekt im Status „inserted“ und kann sich daher nicht im Status „modified“ befinden. Folgender Workaround funktioniert:

    Nicht das Objekt aus dem Kontext ändern, sondern sich das FahrzeugKo nochmal explizit per QueryProvider.getById() holen und darauf dann den Update machen.

    Dass ein Feld „Referenznummer“ in der Buchung existiert, lässt darauf schliessen, dass es sich hier eigentlich um eine 1:1-Verknüpfung zwischen Fahrzeugko und Buchung handelt. Vielleicht genügt der Verweis von der Buchung aus ja schon und man muss nicht zwingend gegenseitig verweisen?

    #8075
    Josef Hopfgartner
    Teilnehmer

    Danke für die Lösung – mit dem Nachladen des BOs funktioniert das Update.

    Demnach war der Wiki-Beispiel-Eintrag zu IFR nicht (mehr) aktuell. Eigentlich schade, dass in der IFR das Objekt vorhanden ist und nicht mehr verändert werden kann.

    Zu meinen Absichten:
    Ich bilde tatsächlich eine 1:1 Beziehung ab.
    Ich beabsichtige, eine Kostenrechnung zu führen.
    Als erstes BO habe ich das Fahrtenbuch eingeführt.
    Weitere BO sind in Ausarbeitung.
    Jedes BO soll eine oder mehrere Buchungen anlegen können – und zwar nach den Regeln der doppelten Buchhaltung.

    Eine Referenz von Buchung auf Fahrtenbuch ist daher nicht möglich, weil es noch andere BOs gibt, die ebenfalls als Referenz gelten können.

    Ich evaluiere gerade „virtuelle BO“, weil diese ja eine solche Anwendung ermöglichen könnten. Demnach wäre es ein DB-VIEW auf alle in zu Betracht kommenden BOs (UNION ALL Klausel).

    #8076
    Ramin Goettlich
    Teilnehmer

    „Buchungen“ klingt nach vielen Datensätzen. Da würde ich von UNION ALL aus Performancegründen eher abraten, insbesondere wenn es viele buchungsauslösende BOs gibt.

    Ausserdem ist ein Referenzfeld auf eine virtuelle Entität (View) kein echter Constraint, d.h. referentielle Integrität wäre dann nicht mehr gesichert und man könnte einen Datensatz aus dem buchungsauslösenden BO löschen, die Buchung würde als Datenleiche bestehen bleiben (wenn man sich nicht selbst zuverlässig um die Löschung kümmert).

    Wie wärs mit einem Referenzfeld je buchungsauslösendem BO in der Buchung? Macht natürlich nur Sinn, wenn überschaubar viele.

    Warum FahrzeugKo auf Buchung verweisen muss, ist mir immer noch nicht klar, aber das funktioniert ja nun. Kann das denn auf Dauer richtig sein, was wenn man z.B. einen FahrzeugKo-Satz stornieren möchte, dann resultiert ggf. eine zweite Buchung daraus – dann klappt damit der 1:1-Beziehung nicht mehr.

    #8077
    Ramin Goettlich
    Teilnehmer

    „Buchungen“ klingt nach vielen Datensätzen. Da würde ich von UNION ALL aus Performancegründen eher abraten, insbesondere wenn es viele buchungsauslösende BOs gibt.

    Ausserdem ist ein Referenzfeld auf eine virtuelle Entität (View) kein echter Constraint, d.h. referentielle Integrität wäre dann nicht mehr gesichert und man könnte einen Datensatz aus dem buchungsauslösenden BO löschen, die Buchung würde als Datenleiche bestehen bleiben (wenn man sich nicht selbst zuverlässig um die Löschung kümmert).

    Wie wärs mit einem Referenzfeld je buchungsauslösendem BO in der Buchung? Macht natürlich nur Sinn, wenn überschaubar viele.

    Warum FahrzeugKo auf Buchung verweisen muss, ist mir immer noch nicht klar, aber das funktioniert ja nun. Kann das denn auf Dauer richtig sein, was wenn man z.B. einen FahrzeugKo-Satz stornieren möchte, dann resultiert ggf. eine zweite Buchung daraus – dann klappt das mit der 1:1-Beziehung nicht mehr.

Ansicht von 7 Beiträgen - 1 bis 7 (von insgesamt 7)