Laden...

NHibernate, Objekt zum bearbeiten "kopieren"

Erstellt von Fracoon vor 16 Jahren Letzter Beitrag vor 15 Jahren 2.115 Views
F
Fracoon Themenstarter:in
85 Beiträge seit 2007
vor 16 Jahren
NHibernate, Objekt zum bearbeiten "kopieren"

verwendetes Datenbanksystem: Postgres

Hi@all...

ich habe eine Klasse Kunde mit einer "List" von ansprechpartner (klasse).

Die Ansprechpartner lass ich mir in einem Datagrid anzeigen.
Habe einen bearbeiten Button, der einen Dialog öffnet indem ich den Ansprechpartner bearbeiten kann. Zur Zeit übergebe ich das Ansprechpartner Objekt an den Dialog und mach ein Databinding an Textboxen. Wenn ich nun Felder verändere werden sie direkt um Objekt verändert. Ich hätte aber gerne einen Abbrechen Button der die Änderungen dann verwirft!

Hab hier und auch bei Codeplex schon einige interessante Artikel zum Thema "Transaktionen auf Objektebene" gelesen. Ist aber alles sehr kompliziert.

Was ich schon versucht habe ist : Objekt Serialisieren => an Dialog übergeben => nur bei OK das Objekt aus der Liste mit dem geänderten Objekt ersetzen.
Das funktioniert soweit auch.

ABER! Ich benutze NHibernate. Beim Speichern des Objekts (Kunde) wirft er eine Exception, dass ein Objekt mit der gleichen ID bereits existiert.

Hat jemand ne Idee wie ich das lösen könnte?

F
Fracoon Themenstarter:in
85 Beiträge seit 2007
vor 16 Jahren

Hab jetzt folgendes gemacht :

Das Ansprechpartner-Objekt wird zuerst mitels Evict aus dem NHibernate cahe entfernt und dann mit dem neuen Objekt ersetzt.

Funktioniert!

Würde mich aber trotzdem über antworten freuen... gibt bestimmt bessere methoden!

Gelöschter Account
vor 16 Jahren

nhibernate lässt dich mit proxies arbeiten. d.h. einfach serialisieren und wieder zurückspielen ist nicht.

1.du hast die möglichkeit alle änderungen an einem objekt das von nhibernate verwaltet bzw überwacht wird, zu verwerfen.
2. du benutzt kein binding, und schreibst die werte in diene klasse erst dann, wenn diese drinn stehen sollen (das wäre mein lösungsvorschlag, da in ein persistenzobjekt nur sachen reingehören, die auch wirklich persistent sein sollen und diese bedingung trifft in diesem fall erst zu wenn der user mit ok bestätigt)
3. du benutzt serialisierung, jedoch beim bestätigen, kopierst du die werte der properties in das originalobjekt (das ist ein wenig dirty)

F
Fracoon Themenstarter:in
85 Beiträge seit 2007
vor 16 Jahren

Danke fü die Antwort. Hab grade gemerkt das die serialisierung tatsächlich nicht funktioniert wenn das Objekt aus der Datenbank kommt...

zu deinen Lösungsvorschlägen :

zu 1 : Wie geht das? Klingt sehr interessant wenn es einfach zu implementieren ist!
zu 2 : Hab ich mir auch shcon gedacht. Ist aber bei Objekten mit vielen Properties ein RIESEN aufwand!
zu 3 : auch seeeehr viel Aufwand!

Gelöschter Account
vor 16 Jahren

das problem an lösung 1 ist, das alle änderungen noch mal neu gelden werden. d.h. ALLE änderungen, die der user z.b. schon bestätigt hat, die aber noch nciht in die datenbank geschrieben wurden, auch verloren gehen.

ich würde dir definitiv lösung 2 empfehlen, da man somit auch datenhaltung/logik/UI besser trennen kann.

F
Fracoon Themenstarter:in
85 Beiträge seit 2007
vor 16 Jahren

Hab jetzt was ähnliches wie deinen 2. Lösungsansatz implementiert :

Hab mir in der Ansprechpartner Klasse eine Statische methode geschrieben die einen Ansprechpartner mit einem anderen vergleicht und veränderte werte überschreibt.

Bevor nun das Bearbeiten fenster geöffnet wird erstelle ich einen neuen Ansprechparter un jage ihn zusammen mit dem "originalen" ansprechpartner durch diese methode. So bekomme ich eine "Kopie". Wenn der Benutzer dann auf Übernehmen klickt mache ich das ganze umgekehrt. Wenn er abbrechen klickt passiert nichts..

Ist halt ein "hoher" Aufwand wenn der Ansprechpartner Klasse felder hinzugefügt werden sollen!

Aber denke so bin ich auf dem sichersten weg!

Gelöschter Account
vor 16 Jahren

stichwort:
IClonable

F
Fracoon Themenstarter:in
85 Beiträge seit 2007
vor 16 Jahren

Schau ich mir an danke!

F
10.010 Beiträge seit 2004
vor 16 Jahren

Ich würde evtl ersteinmal schauen, ob deine Objecte IEditableObject implementieren.
Das ist eines der vielen Interfaces, die einem die Arbeit erleichtern.

Das Interface hat u.a. ein CancelEdit, was genau das macht was Du brauchst.

Wenn NHibernate objekte das also implementieren reicht ein:


IEditableObject ie = DeinObject as IEditableObject;
if( ie != null )
  ie.CancelEdit();

F
Fracoon Themenstarter:in
85 Beiträge seit 2007
vor 16 Jahren

Danke für den Tipp FZelle.

Ich vermute mal wenn bei ie.CancelEdit(); eine NullReference Exception kommt, heißt das, dass die Klasse IeditableObject nicht implementiert?!!?

F
Fracoon Themenstarter:in
85 Beiträge seit 2007
vor 16 Jahren

Für alle die es interessiert, ich hab jetzt folgendes gemacht :


public class ansprechpartner : IEditableObject
    {
        Hashtable props = null;
        
        private long ansprechpartner_id;
        private string vorname;
        private string nachname;
        private string email;
        private string telefon;
        private kunde kunde_fk;
        private int version;


        #region Fields
        public virtual long Ansprechpartner_id
        {
            get { return ansprechpartner_id; }
            set { ansprechpartner_id = value; }
        }
        
        public virtual string Vorname
        {
            get { return vorname; }
            set { vorname = value; }
        }
        
        public virtual string Nachname
        {
            get { return nachname; }
            set { nachname = value; }
        }
        
        public virtual string Email
        {
            get { return email; }
            set { email = value; }
        }
        
        public virtual string Telefon
        {
            get { return telefon; }
            set { telefon = value; }
        }
        public virtual kunde Kunde_fk
        {
            get { return kunde_fk; }
            set { kunde_fk = value; }
        }
        public virtual int Version
        {
            get { return version; }
            set { version = value; }
        }
 
        #endregion

        public virtual void BeginEdit()
        {
            

            //enumerate properties

            PropertyInfo[] properties = (this.GetType()).GetProperties
                        (BindingFlags.Public | BindingFlags.Instance);

            props = new Hashtable(properties.Length - 1);

            for (int i = 0; i < properties.Length; i++)
            {
                //check if there is set accessor

                if (null != properties[i].GetSetMethod())
                {
                    object value = properties[i].GetValue(this, null);
                    props.Add(properties[i].Name, value);
                }
            }
        }
        public virtual void CancelEdit()
        {
            //check for inappropriate call sequence

            if (null == props) return;

            //restore old values

            PropertyInfo[] properties = (this.GetType()).GetProperties
                (BindingFlags.Public | BindingFlags.Instance);
            for (int i = 0; i < properties.Length; i++)
            {
                //check if there is set accessor

                if (null != properties[i].GetSetMethod())
                {
                    object value = props[properties[i].Name];
                    properties[i].SetValue(this, value, null);
                }
            }

            //delete current values

            props = null;
        }
        public virtual void EndEdit()
        {
            //delete current values

            props = null;
        }



        
    }

Funktioniert bist jetzt ganz gut! Unf vor allem muss man nicht für jede Property die man hinzufügt noch etwas an der "Transaktionslogik" ändern!

Edit : Ist übrigens von Codeproject "geklaut"!

F
10.010 Beiträge seit 2004
vor 16 Jahren

Wenn du bei ie.CancelEdit eine Exception bekommst, hast Du evtl den sinn von "as"
nicht so ganz verinnerlicht.

Und wenn Du schon anfängst, bitte implementiere auch gleich IPropertyChanged
und IDataErrorInfo, dann macht es noch mehr "Spass".

Auch würde ich das dann gleich in ein BasisObject auslagern,
und Rules einbauen....

F
Fracoon Themenstarter:in
85 Beiträge seit 2007
vor 16 Jahren

Danke FZelle für die tipps!

Hab jetzt mit meiner implementierung noch ein anderes problem!

Hab BEginEdit CancelEdit und EndEdit nun in eine eigene Klasse gepackt. Meine Kunde und Ansprechpartner erben davon!

Funtioniert soweit!

Aber : Der Kunde hat eine List<ansprechpartner>. Für die geht es nicht. Ich vermute, dass beim "kopieren" der Properties für List<> nur eine Referenz übergeben wird!
Ist das richtig? Kann man das irgendwie so generisch lösen wie für die anderen Properties?

F
10.010 Beiträge seit 2004
vor 16 Jahren

Das ist ein komplexeres Problem.

Willst Du wirklich die ganze liste Clonen?
Macht das sinn?

R
494 Beiträge seit 2006
vor 16 Jahren

...und Rules einbauen....

Hallo,
was meinst du genau damit?

F
10.010 Beiträge seit 2004
vor 16 Jahren

Validation in form von Rules ( Regeln ).

"Beliebt" ist da eine Rulesengine wie in CSLA.

F
Fracoon Themenstarter:in
85 Beiträge seit 2007
vor 16 Jahren

Das ist ein komplexeres Problem.

Willst Du wirklich die ganze liste Clonen?
Macht das sinn?

Sinn des ganzen wäre, dass ich für den gesamten Kunden eine "Undo" Funktion habe! (wenn man auf Abbrechen im Bearbeiten-Fenster klickt)!!

742 Beiträge seit 2005
vor 15 Jahren

Entschuldigung dass ich diesen alten Beitrag nochmal ausgrabe, aber er trifft mein Problem ganz gut. Ich möchte ebenfalls NHibernate Klassen kopieren, stehe aber vor dem gleichen Problem mit den Collections (habe erst den Vorschlag aus MSDN probiert, aber das ist das gleiche).

Hat jemand eine generische Methode gefunden (oder wenigstens eine einfache) auch den Status von Collections derart zu sichern?