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?
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!
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)
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!
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.
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!
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();
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ü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"!
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....
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?
Das ist ein komplexeres Problem.
Willst Du wirklich die ganze liste Clonen?
Macht das sinn?
...und Rules einbauen....
Hallo,
was meinst du genau damit?
Validation in form von Rules ( Regeln ).
"Beliebt" ist da eine Rulesengine wie in CSLA.
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)!!
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?
ImageTools for Silverlight: http://imagetools.codeplex.com | http://www.silverdiagram.net | http://www.cleancodedeveloper.de b:::