Architecture Team Scratch Pad - Exceptions, Transactions, Sessions, Data Transfer Object, ...: Difference between revisions
No edit summary |
|||
Line 47: | Line 47: | ||
5bc) <code>throw Exp</code> (''mit gesetzter InnerException!'') | 5bc) <code>throw Exp</code> (''mit gesetzter InnerException!'') | ||
Line 82: | Line 79: | ||
* Haben eine interne ID, welche im Konstruktor generiert wird (<code>int FSessionID</code>) | * Haben eine interne ID, welche im Konstruktor generiert wird (<code>int FSessionID</code>) | ||
* Haben ein <code>Dictionary<string, ISessionTargetObjectInterface> FSessionTargetObjects</code> | * Haben ein <code>Dictionary<string, ISessionTargetObjectInterface> FSessionTargetObjects</code> | ||
** <code>ISessionTargetObjectInterface</code> braucht Methoden <code> | ** <code>ISessionTargetObjectInterface</code> braucht Methoden <code>TDataTransferObject GetData(TSession ASession)</code> (3-fach ueberladen) und <code>TSubmitChangesResult SubmitChanges(TSession ASession, TDataTransferObject ADTO)</code> | ||
** <code>ISessionTargetObjectInterface</code> braucht <code>void BeforeCommit(TSession ASession)</code> & <code>void AfterCommit(TSession ASession)</code> und <code>void BeforeRollback(TSession ASession)</code> & <code>void AfterRollback(TSession ASession)</code>-Methoden sowie eine <code>void StartTransaction(TSession ASession, IsolationLevel AIsolationLevel)</code>-Methode | ** <code>ISessionTargetObjectInterface</code> braucht <code>void BeforeCommit(TSession ASession)</code> & <code>void AfterCommit(TSession ASession)</code> und <code>void BeforeRollback(TSession ASession)</code> & <code>void AfterRollback(TSession ASession)</code>-Methoden sowie eine <code>void StartTransaction(TSession ASession, IsolationLevel AIsolationLevel)</code>-Methode | ||
*** Über den Isolation-Level bin ich nach wie vor unglücklich. Ich will den gar nicht: Ist eine Fehlerquelle. Die Entwickler sollen lieber bewußt entscheiden, welche Daten sie mit <code>SELECT * FROM >table< WHERE >condition< FOR UPDATE</code> sperren. --[[User:Thiasg|Thiasg]] 13:07, 16 May 2011 (UTC) | *** Über den Isolation-Level bin ich nach wie vor unglücklich. Ich will den gar nicht: Ist eine Fehlerquelle. Die Entwickler sollen lieber bewußt entscheiden, welche Daten sie mit <code>SELECT * FROM >table< WHERE >condition< FOR UPDATE</code> sperren. --[[User:Thiasg|Thiasg]] 13:07, 16 May 2011 (UTC) | ||
Line 95: | Line 92: | ||
**** Diese Verstaendigungen dienen nicht zum DB-Transaktionshandling in solcherart registrierten Objekten, sondern um e.g. externe Resourcen konsistent zu halten. | **** Diese Verstaendigungen dienen nicht zum DB-Transaktionshandling in solcherart registrierten Objekten, sondern um e.g. externe Resourcen konsistent zu halten. | ||
* Haben eigene <code>Save()</code>- und <code>Rollback(string)</code>-Methoden sowie eine <code>RollbackToLastSavepoint()</code>-Methode [nur wenn wir Savepoints implementieren koennen] | * Haben eigene <code>Save()</code>- und <code>Rollback(string)</code>-Methoden sowie eine <code>RollbackToLastSavepoint()</code>-Methode [nur wenn wir Savepoints implementieren koennen] | ||
* Ich würde die Methoden AddSavepoint(), bzw. RollBackToSavepoint(string) nennen. Dann werden sie nicht mit Save im Sinne von Abspeichern und kompletten Rollback verwechselt. Diese beiden Methoden sind die Kür, bei der unklar ist, ob sie gebraucht werden. Evtl. sind sie bei einem Wizard hilfreich. Dann müssen sie aber vom Client aufrufbar sein. --[[User:Thiasg|Thiasg]] 13:11, 16 May 2011 (UTC) | ** Ich würde die Methoden AddSavepoint(), bzw. RollBackToSavepoint(string) nennen. Dann werden sie nicht mit Save im Sinne von Abspeichern und kompletten Rollback verwechselt. Diese beiden Methoden sind die Kür, bei der unklar ist, ob sie gebraucht werden. Evtl. sind sie bei einem Wizard hilfreich. Dann müssen sie aber vom Client aufrufbar sein. --[[User:Thiasg|Thiasg]] 13:11, 16 May 2011 (UTC) | ||
*** Umbenennen macht Sinn. | |||
*** Ob wir diese Methoden von der Clientseite aufrufen lassen muessen wir uns anhand konkreter Problemstellungen ueberlegen. (Derzeit jedenfalls nicht aktuell, weil wir noch gar nicht wissen, ob wir Savepoints implementieren koennen) --[[User:Christiankatict|Christiankatict]] 13:41, 18 May 2011 (UTC) | |||
** Wirken direkt auf <code>FDBAccessObj</code> | ** Wirken direkt auf <code>FDBAccessObj</code> | ||
*** Die <code>string Save()</code>-Methode akzeptiert keinen String (im Gegensatz zu der ADO.NET-Methode!), sondern liefert einen eindeutigen String zurueck (e.g. interne ID + Serverzeit in Millisekunden) | *** Die <code>string Save()</code>-Methode akzeptiert keinen String (im Gegensatz zu der ADO.NET-Methode!), sondern liefert einen eindeutigen String zurueck (e.g. interne ID + Serverzeit in Millisekunden) | ||
* Haben eine <code> | * Haben eine <code>TDataTransferObject GetData()</code>-Methode | ||
** diese Methode... | ** diese Methode... | ||
*** erzeugt eine Instanz eines 'Data Transfer Object' vom neuen Typ '<code>TDataTransferObject</code>' (siehe unten) | *** erzeugt eine Instanz eines 'Data Transfer Object' vom neuen Typ '<code>TDataTransferObject</code>' (siehe unten) | ||
*** ruft die Methode <code>GetData()</code> in einer for-loop auf 1..n <code>ISessionTargetObjectInterface</code>-Objekten auf | *** ruft die Methode <code>GetData()</code> in einer for-loop auf 1..n <code>ISessionTargetObjectInterface</code>-Objekten auf | ||
*** fuegt jedes von diesen Methoden retournierte <code>TTypedDataSet</code> mittels Methode '<code>void AddDataSet(TTypedDataSet ADataSet)</code>' in die vom Data Transfer Object gehaltene Liste von Typed DataSets ein. | *** fuegt jedes von diesen Methoden retournierte <code>TTypedDataSet</code> mittels Methode '<code>void AddDataSet(TTypedDataSet ADataSet)</code>' in die vom Data Transfer Object gehaltene Liste von Typed DataSets ein. | ||
* Haben eine <code>TSubmitChangesResult SubmitChanges(ref | * Haben eine <code>TSubmitChangesResult SubmitChanges(ref TDataTransferObject ADTO)</code>-Methode | ||
** diese Methode... | ** diese Methode... | ||
*** akzeptiert ein 'Data Transfer Object'-Instanz vom neuen Typ '<code>TDataTransferObject</code>' (siehe unten) | *** akzeptiert ein 'Data Transfer Object'-Instanz vom neuen Typ '<code>TDataTransferObject</code>' (siehe unten) | ||
*** ruft die Methode <code>TSubmitChangesResult SubmitChanges(TSession ASession, | *** ruft die Methode <code>TSubmitChangesResult SubmitChanges(TSession ASession, TDataTransferObject ADTO)</code> in einer for-loop auf 1..n <code>ISessionTargetObjectInterface</code>-Objekten auf | ||
**** wenn bei einem Aufruf ein Fehler auftritt, duerfen die weiteren Aufrufe nicht mehr durchgefuehrt werden | **** wenn bei einem Aufruf ein Fehler auftritt, duerfen die weiteren Aufrufe nicht mehr durchgefuehrt werden | ||
*** meldet jeglichen Fehler zum Client | *** meldet jeglichen Fehler zum Client | ||
====Base Classes==== | ====Base Classes==== | ||
Line 120: | Line 118: | ||
* evtl. zukuenftigte private Class '<code>SessionTargetObjectBaseExternalSystems</code>'. Implementiert <code>ISessionTargetObjectInterface</code> (oder erbt von <code>SessionTargetObjectBaseEmpty</code>) | * evtl. zukuenftigte private Class '<code>SessionTargetObjectBaseExternalSystems</code>'. Implementiert <code>ISessionTargetObjectInterface</code> (oder erbt von <code>SessionTargetObjectBaseEmpty</code>) | ||
** beliebige Implementationsdetails... | ** beliebige Implementationsdetails... | ||
==Data Transfer Object== | ==Data Transfer Object== | ||
Line 125: | Line 124: | ||
Es wuerde die bisher eingesetzten strongly Typed DataSets ersetzen. Der Vorteil liegt v.a. in der Flexibilitaet, 1..n TTypedDataSets halten zu koennen. | Es wuerde die bisher eingesetzten strongly Typed DataSets ersetzen. Der Vorteil liegt v.a. in der Flexibilitaet, 1..n TTypedDataSets halten zu koennen. | ||
* Enthaelt 0..n TTypedDataSet-Objekte, welche mit String-Identifier oder Index ansprechbar sind | * Enthaelt 0..n TTypedDataSet-Objekte, welche mit String-Identifier oder Index ansprechbar sind | ||
** intern in einem <code>Dictionary<string, TTypedDataSet> FDataSets</code> abgelegt | ** intern in einem <code>Dictionary<string, TTypedDataSet> FDataSets</code> abgelegt | ||
Line 136: | Line 131: | ||
*** ''Problem mit diesem Ansatz'': sollte es Definitionen von 'CustomRelations' in der XML-Datei welche die TTypedDataSets spezifiziert geben welche 'CustomTables' mit 'Tables' in demselbem DataSet verknuepft, so wuerden diese Relations nicht machbar sein wenn die betroffenen DataTables in unterschiedlichen DataSets zu finden sind! | *** ''Problem mit diesem Ansatz'': sollte es Definitionen von 'CustomRelations' in der XML-Datei welche die TTypedDataSets spezifiziert geben welche 'CustomTables' mit 'Tables' in demselbem DataSet verknuepft, so wuerden diese Relations nicht machbar sein wenn die betroffenen DataTables in unterschiedlichen DataSets zu finden sind! | ||
* Hat Methoden '<code>void AddDataSet(TTypedDataSet ADataSet)</code>' sowie '<code>TTypedDataSet GetDataSet(string ADataSetName)</code>' und <code>TTypedDataSet GetDataSet(int ADataSetIndex)</code>. | * Hat Methoden '<code>void AddDataSet(TTypedDataSet ADataSet)</code>' sowie '<code>TTypedDataSet GetDataSet(string ADataSetName)</code>' und <code>TTypedDataSet GetDataSet(int ADataSetIndex)</code>. | ||
* Das 'Data Transfer Object' wird bei <code> | * Das 'Data Transfer Object' wird bei <code>TDataTransferObject GetData(...)</code> und bei <code>SubmitChanges(TDataTransferObject ADTO, ...)</code> uebermittelt. Es werden daher nicht laenger direkt strongly Typed DataSets (eg. <code>PartnerEditTDS</code>) uebergeben! | ||
Line 153: | Line 139: | ||
*** Dann fordert er sich auch eine Session an und hat damit eine DB Session :-) --[[User:Thiasg|Thiasg]] 12:58, 16 May 2011 (UTC) | *** Dann fordert er sich auch eine Session an und hat damit eine DB Session :-) --[[User:Thiasg|Thiasg]] 12:58, 16 May 2011 (UTC) | ||
**** Das ist durchaus ein Ansatz, darueber sollten wir noch mehr nachdenken. --[[User:Christiankatict|Christiankatict]] 13:27, 18 May 2011 (UTC) | **** Das ist durchaus ein Ansatz, darueber sollten wir noch mehr nachdenken. --[[User:Christiankatict|Christiankatict]] 13:27, 18 May 2011 (UTC) | ||
==DB Transactions spanning multiple Server calls== | |||
'''TODO''' | |||
==BackgroundworkManager Object (geringe Prioritaet)== | |||
* Globales Objekt auf Clientseite um 'delayed data loading' komplett in Hintergrund-Threads abwickeln zu koennen (e.g. im Partner Edit Screen: Daten fuer 'Addresses'- und 'Subscriptions'-Tabs immer im Hintergrund laden, auch wenn zu allererst ein anderes Tab [e.g. 'Partner Types'] vom User geoeffnet wurde) | |||
** Hat einen ''internen'' Thread-Pool von max. eg. 3 'Worker Threads', die von beliebigen Stellen im Client fuer Hintergrundaufgaben herangezogen werden koennen, wenn diese Hintergrundaufgaben nicht innerhalb einer bestimmten Zeit ausgefuehrt werden muessen | |||
*** Wuerden mehr Worker Threads angefordert als im internen 'Thread Pool' abgearbeitet werden koennen, wuerden diese Anfragen in eine Queue gestellt. Diese 'gequeueten' Anfragen wuerden nach und nach in den 'Thread Pool' rutschen und anschliessend abgearbeitet werden, sobald mindestens einer der bisher laufenden Threads im 'Thread Pool' beendet wurde. | |||
** Aufpassen: Synchroniserung des Datenladens so absichern dass sicher keine (evtl. veraenderten) lokalen Daten ueberschrieben werden koennen, egal wie lange der asynchrone Servercall dauert (der Benutzer koennte inzwischen lokale Daten geaendert haben die mit dem Rueckgabewert des Servercalls ueberschrieben werden koennten)!!! | |||
==Weitere Diskussionspunkte== | ==Weitere Diskussionspunkte== | ||
????? | ????? |
Latest revision as of 13:41, 18 May 2011
DISCLAIMER: SCRATCH PAD ONLY!
This page is a dumping ground of things that are currently discussed between ChristianK and ThiasG.
THIS PAGE DOES NOT LAY DOWN A CURRENT OR FUTURE POLICY. SPECIFICALLY, YOU SHOULD NOT IMPLEMENT ANYTHING MENTIONED ON THIS PAGE OR BASE A CURRENT IMPLEMENTATION ON ASSUMPTIONS THAT SOMETHING IN THIS PAGE MIGHT/WILL BECOME REALITY.
There is no reason why you should not read this, but there is absolutely no guarantee that any of the content pasted in here will become reality in some form or other. Our thinking on some of the topics is not finished yet but we need a place to write things down so we can collaborate well, and this is the place for it.
(Some or all of this page may be written in German. Sorry about this!)
Wrapper-Objekt fuer Connector-Klassen
Konzept
Ein Wrapper-Objekt soll automatisch fuer jede serverseitige Klasse erzeugt werden, die mit einem neu zu schaffendem C#-Attribut ClientConnectorAttribute()
dekoriert ist (nant generateORM
soll diese Klassen generieren). Die (nicht-statische) serverseitige Klasse selbst wird zum Zielobjekt, dass fuer den Client transparent in dem (nicht-statischen) Wrapper-Objekt abgebildet wird. (Dies ist sehr aehnlich zu dem Konzept der 'Instantiators' - ja sogar so aehnlich, dass die 'Instantiators' die Wrapper-Objekt-Funktionen bekommen koennten und auf 'Wrapper' umbenannt werden koennten!).
Der Client ruft Methoden auf dem Wrapper-Objekt auf und gibt immer einen SessionIdentifier mit (diesen hat der Client bekommen, als er beim oeffnen eines Screens den Session Manager um eine neue Session bat). Anhand des SessionIdentifiers holt das Wrapper-Objekt die korrekte Instanz der Session und gibt diese Instanz an alle Methoden weiter, die es im Zielobjekt aufruft.
Das Wrapper-Objekt kuemmert sich auch um die Steuerung der DB Transactions (siehe naechster Absatz). Allerdings macht das Wrapper-Objekt nie ein Commit automatisch; Commits muss der Programmierer manuell an beliebigen Punkten in seinem Code im Zielobjekt machen!!! (Commits und Rollbacks erfolgen auf dem Session Object und nicht direkt auf GDBAccessObj
!!!)
Abfolge von Methodenaufrufen die vom Client kommen (komplett generierter Code!)
1) Instanz der Session vom SessionManager holen (anhand des SessionIdentifiers)
2) DB Transaction starten (mit erforderlichem IsolationLevel, welcher in einem Argument des neu zu schaffendem C# Attributs RemoteCall()
spezifiziert werden muss)
3) try
3a) Aufruf von eigentlicher Methode im Zielobjekt (diese Methode muss im Zielobjekt mit dem C# Attribut ClientConnectorMethodAttribute()
dekoriert sein; dadurch wird diese Methode in diesem Wrapper vorhanden sein). Die Instanz der Session wird als erstes Argument mitgegeben.
4) catch(Exception Exp)
4a) spezifisches Logging (Methodennamen und Zielobjekt erwaehnen) + LogStrackTrace
4b) Wert von Exp
in internen Variable merken!
4c) throw Exp
5) finally
(IMMER)
5a) try
5aa) DB Rollback
5b) catch(Exception Exp)
5ba) spezifisches Logging (Methodennamen und Zielobjekt erwaehnen) & spezieller Hinweis auf unerwartete Rollback-Exception + LogStrackTrace
5bb) Exp.InnerException
auf zuvor gemerkte InnerException
setzen!
5bc) throw Exp
(mit gesetzter InnerException!)
Sessions
Konzept
Derzeit koennen Daten am Server zwischen unterschiedlichen Servercalls nur erhalten bleiben, wenn UIConnectors verwendet werden und diese durch den 'KeepAlive'-Prozess 'am Leben' gehalten werden (sie sind stateful objects).
Durch die Einfuehrung von 'Sessions' koennte auf stateful objects und daher auf UIConnectors und das 'am-Leben-halten' dieser Objekte verzichtet werden (die statischen WebConnectors koennten anstelle der UIConnectors treten und dann einfach nur noch 'Connectors' heissen). Dies wuerde geringere Komplexitaet und erhoehte Flexibilitaet bedeuten, denn mit 'Sessions' koennen Daten beliebig lange im Serverspeicher gehalten werden, wenn dies noetig sein sollte. Dies kann fuer komplexe Client-Server-Abwicklungen vom Vorteil sein (u.a. fuer DB Transactions spanning multiple Server calls) und auch, wenn der 'Client' etwa eine Website oder irgendein serverseitiges Skript ist, das stateful objects nicht mittels KeepAlive-Signalen 'am Leben halten' koennte (so ein Client beherrscht naemlich womoeglich gar kein .NET Remoting).
Uebersicht ueber die Implementation
- Es wuerde ein Session Manager-Objekt auf der Serverseite geben
- ein globales Objekt pro AppDomain [=Client Session]
- Pro Kontext (e.g. Screen) wuerde auf Anforderung vom Client eine separate Session auf dem Server erzeugt werden (2 Partner Edit Screens parallel geoeffnet = 2 Sessions offen)!
- Daraus ergibt sich, dass wir kein 'globales' Session-Objekt fuer eine AppDomain [=Client Session] haben (nicht wie in ASP.NET)!
Session Manager
Globaler, statischer 'Session Manager' TSessionManager
(neu zu schaffen und einmal beim Einrichten der Client AppDomain zu erzeugen) muss folgendes erlauben und neu das zu schaffende Interface ISessionManagerInterface
implementieren:
string CreateSession()
[erzeugt ein neues Session-Objekt und liefert dessen Session Identifier zurueck],void CloseSession(string SessionIdentifier)
[verwirft die Session und somit alle ihre von ihr gehaltenen Daten].- Hat eine Methode
string CreateSession(out TSession ASession)
[erzeugt ein neues Session-Objekt und liefert dessen Session Identifier sowie die erzeugte Session zurueck]. Diese Methode wird nicht im Interface deklariert, denn sie darf nur auf Server-seite verwendet werden (Sessions werden nicht remoted!) - Hat eine Methode
TSession GetSession(string ASessionIdentifier)
. Diese Methode wird nicht im Interface deklariert, denn sie darf nur auf Server-seite verwendet werden (Sessions werden nicht remoted!) - Referenz zu dieser
TSessionManager
-Instanz wuerde zukuenftig einmalig beiTClientManager.ConnectClient(...)
alsISessionManagerInterface
zum Client remotedISessionManagerInterface
muss dafuer in einer *.Shared.*.DLL deklariert seinTSessionManager
muss daher nicht in einer *.Shared.*.DLL deklariert sein, sondern kann und soll in einer *.Server.*.DLL deklariert sein
- Hat ein
Dictionary<string, TSession> FSessions
- Der Dictionary-
string
-Key ist derSessionIdentifier
- Der Dictionary-
Session Objects
'Session'-Objekte (TSession
, neu zu schaffen) wuerden nur auf Serverseite existieren (werden nicht remoted)!
- Lifetime
- Wird von Client kontrolliert werden (z.b. beim Screen-oeffnen und schliessen):
TSessionManager.CreateSession()
,TSessionManager.CloseSession()
.
- Wird von Client kontrolliert werden (z.b. beim Screen-oeffnen und schliessen):
- Haben einen Session Identifier (string mit GUID als Inhalt), welcher im Konstruktor generiert wird (readonly Property
string SessionIdentifier
) - Haben eine interne ID, welche im Konstruktor generiert wird (
int FSessionID
) - Haben ein
Dictionary<string, ISessionTargetObjectInterface> FSessionTargetObjects
ISessionTargetObjectInterface
braucht MethodenTDataTransferObject GetData(TSession ASession)
(3-fach ueberladen) undTSubmitChangesResult SubmitChanges(TSession ASession, TDataTransferObject ADTO)
ISessionTargetObjectInterface
brauchtvoid BeforeCommit(TSession ASession)
&void AfterCommit(TSession ASession)
undvoid BeforeRollback(TSession ASession)
&void AfterRollback(TSession ASession)
-Methoden sowie einevoid StartTransaction(TSession ASession, IsolationLevel AIsolationLevel)
-Methode- Über den Isolation-Level bin ich nach wie vor unglücklich. Ich will den gar nicht: Ist eine Fehlerquelle. Die Entwickler sollen lieber bewußt entscheiden, welche Daten sie mit
SELECT * FROM >table< WHERE >condition< FOR UPDATE
sperren. --Thiasg 13:07, 16 May 2011 (UTC)- Darueber muessen wir noch mehr reden. --Christiankatict 13:24, 18 May 2011 (UTC)
- Über den Isolation-Level bin ich nach wie vor unglücklich. Ich will den gar nicht: Ist eine Fehlerquelle. Die Entwickler sollen lieber bewußt entscheiden, welche Daten sie mit
- Haben eine Methode '
void RegisterSessionTargetObject(string ASessionTargetName, ISessionTargetObjectInterface ASessionTarget)
' fuer das registrieren von beliebig vielen 'Target Objects'. - Haben eine eigene DB Connection (
TDataBase FDBAccessObj
) auf der die DB Transactions durchgefuehrt werden- Damit wuerde es moeglich, dass man 'nested Transactions' nachbildet (welche es in ADO.NET nicht gibt), indem man mehrere 'Sessions' oeffnet (und damit mehrere DB Connections) und die DB Transactions auf diesen sehr sorgfaeltig koordiniert.
- Haben eigene
CommitTransaction()
- undRollbackTransaction()
-Methoden- Wirken direkt auf
FDBAccessObj
.- Zusaetzlich: jeder
Commit()
-Aufruf erzeugt gleich wieder eine neue DB Transaction aufFDBAccessObj
(mit demselben IsolationLevel als die gerade committete Transaction!) und ruft dievoid StartTransaction(TSession ASession, IsolationLevel AIsolationLevel)
-Methode in einer for-loop auf 1..nISessionTargetObjectInterface
-Objekten auf - Zusaetzlich: jeder
Commit()
- undRollback
-Aufruf ruft in einer for-loop 1..nISessionTargetObjectInterface
-Objekte.BeforeCommit
&.AfterCommit
/ bzw.BeforeRollback
&.AfterRollback-Methoden
auf!- Diese Verstaendigungen dienen nicht zum DB-Transaktionshandling in solcherart registrierten Objekten, sondern um e.g. externe Resourcen konsistent zu halten.
- Zusaetzlich: jeder
- Wirken direkt auf
- Haben eigene
Save()
- undRollback(string)
-Methoden sowie eineRollbackToLastSavepoint()
-Methode [nur wenn wir Savepoints implementieren koennen]- Ich würde die Methoden AddSavepoint(), bzw. RollBackToSavepoint(string) nennen. Dann werden sie nicht mit Save im Sinne von Abspeichern und kompletten Rollback verwechselt. Diese beiden Methoden sind die Kür, bei der unklar ist, ob sie gebraucht werden. Evtl. sind sie bei einem Wizard hilfreich. Dann müssen sie aber vom Client aufrufbar sein. --Thiasg 13:11, 16 May 2011 (UTC)
- Umbenennen macht Sinn.
- Ob wir diese Methoden von der Clientseite aufrufen lassen muessen wir uns anhand konkreter Problemstellungen ueberlegen. (Derzeit jedenfalls nicht aktuell, weil wir noch gar nicht wissen, ob wir Savepoints implementieren koennen) --Christiankatict 13:41, 18 May 2011 (UTC)
- Wirken direkt auf
FDBAccessObj
- Die
string Save()
-Methode akzeptiert keinen String (im Gegensatz zu der ADO.NET-Methode!), sondern liefert einen eindeutigen String zurueck (e.g. interne ID + Serverzeit in Millisekunden)
- Die
- Ich würde die Methoden AddSavepoint(), bzw. RollBackToSavepoint(string) nennen. Dann werden sie nicht mit Save im Sinne von Abspeichern und kompletten Rollback verwechselt. Diese beiden Methoden sind die Kür, bei der unklar ist, ob sie gebraucht werden. Evtl. sind sie bei einem Wizard hilfreich. Dann müssen sie aber vom Client aufrufbar sein. --Thiasg 13:11, 16 May 2011 (UTC)
- Haben eine
TDataTransferObject GetData()
-Methode- diese Methode...
- erzeugt eine Instanz eines 'Data Transfer Object' vom neuen Typ '
TDataTransferObject
' (siehe unten) - ruft die Methode
GetData()
in einer for-loop auf 1..nISessionTargetObjectInterface
-Objekten auf - fuegt jedes von diesen Methoden retournierte
TTypedDataSet
mittels Methode 'void AddDataSet(TTypedDataSet ADataSet)
' in die vom Data Transfer Object gehaltene Liste von Typed DataSets ein.
- erzeugt eine Instanz eines 'Data Transfer Object' vom neuen Typ '
- diese Methode...
- Haben eine
TSubmitChangesResult SubmitChanges(ref TDataTransferObject ADTO)
-Methode- diese Methode...
- akzeptiert ein 'Data Transfer Object'-Instanz vom neuen Typ '
TDataTransferObject
' (siehe unten) - ruft die Methode
TSubmitChangesResult SubmitChanges(TSession ASession, TDataTransferObject ADTO)
in einer for-loop auf 1..nISessionTargetObjectInterface
-Objekten auf- wenn bei einem Aufruf ein Fehler auftritt, duerfen die weiteren Aufrufe nicht mehr durchgefuehrt werden
- meldet jeglichen Fehler zum Client
- akzeptiert ein 'Data Transfer Object'-Instanz vom neuen Typ '
- diese Methode...
Base Classes
- Private Base Class '
SessionTargetObjectBaseEmpty
'. ImplementiertISessionTargetObjectInterface
- implementiert leere Methoden
void BeforeCommit(TSession ASession)
&void AfterCommit(TSession ASession)
undvoid BeforeRollback(TSession ASession)
&void AfterRollback(TSession ASession)
-Methoden sowie leerevoid StartTransaction(TSession ASession, IsolationLevel AIsolationLevel)
-Methode
- implementiert leere Methoden
- Private Base Class '
SessionTargetObjectBaseDataSet
'. Erbt vonSessionTargetObjectBaseEmpty
- hat
protected TTypedDataSet FDataSet
- hat
- evtl. zukuenftigte private Class '
SessionTargetObjectCache
'. ImplementiertISessionTargetObjectInterface
- haelt beliebige Daten in beliebigen zu definierenden Strukturen in einem Cache (evtl. ein DataSet mit 1..n DataTables [so wie unser existierender
TCacheableTablesManager
])
- haelt beliebige Daten in beliebigen zu definierenden Strukturen in einem Cache (evtl. ein DataSet mit 1..n DataTables [so wie unser existierender
- evtl. zukuenftigte private Class '
SessionTargetObjectBaseExternalSystems
'. ImplementiertISessionTargetObjectInterface
(oder erbt vonSessionTargetObjectBaseEmpty
)- beliebige Implementationsdetails...
Data Transfer Object
Das 'TDataTransferObject
' (neu zu schaffen) wird ein universelles Objekt zur Uebertragung von Daten vom Server zum Client und vom Client zum Server sein.
Es wuerde die bisher eingesetzten strongly Typed DataSets ersetzen. Der Vorteil liegt v.a. in der Flexibilitaet, 1..n TTypedDataSets halten zu koennen.
- Enthaelt 0..n TTypedDataSet-Objekte, welche mit String-Identifier oder Index ansprechbar sind
- intern in einem
Dictionary<string, TTypedDataSet> FDataSets
abgelegt- im Typed DataSet 'x' (e.g.
PartnerEditTDS
): jetztige TTypedDataSet-Definition (eg.PartnerEditTDS
) ABZUEGLICHCustomTable(s)
. - in 1..n weiteren Typed DataSets: Daten speziell fuer Organisation 'X' oder Organisation 'Y'.
- im Typed DataSet 'CustomTables': enthaelt 1..n
CustomTable(s)
fuer 1..n DataSets welche in 'x' oder in den DataSets fuer andere Organisationen abgelegt sind. - Problem mit diesem Ansatz: sollte es Definitionen von 'CustomRelations' in der XML-Datei welche die TTypedDataSets spezifiziert geben welche 'CustomTables' mit 'Tables' in demselbem DataSet verknuepft, so wuerden diese Relations nicht machbar sein wenn die betroffenen DataTables in unterschiedlichen DataSets zu finden sind!
- im Typed DataSet 'x' (e.g.
- intern in einem
- Hat Methoden '
void AddDataSet(TTypedDataSet ADataSet)
' sowie 'TTypedDataSet GetDataSet(string ADataSetName)
' undTTypedDataSet GetDataSet(int ADataSetIndex)
. - Das 'Data Transfer Object' wird bei
TDataTransferObject GetData(...)
und beiSubmitChanges(TDataTransferObject ADTO, ...)
uebermittelt. Es werden daher nicht laenger direkt strongly Typed DataSets (eg.PartnerEditTDS
) uebergeben!
GBAccess
Object
- Evtl. etwas mehr 'verstecken', denn der Programmierer braucht es i.d.R. nicht mehr zu benutzen, wenn oben aufgefuehrte Arbeitsweisen gaengig werden???
- - ABER es gibt immer noch viele Situationen auf der Serverseite, wo auch in Zukunft keine Sessions benutzt werden (e.g. die vielen Server-interne Dinge die keine Client-Interaktion haben)!
- Dann fordert er sich auch eine Session an und hat damit eine DB Session :-) --Thiasg 12:58, 16 May 2011 (UTC)
- Das ist durchaus ein Ansatz, darueber sollten wir noch mehr nachdenken. --Christiankatict 13:27, 18 May 2011 (UTC)
- Dann fordert er sich auch eine Session an und hat damit eine DB Session :-) --Thiasg 12:58, 16 May 2011 (UTC)
- - ABER es gibt immer noch viele Situationen auf der Serverseite, wo auch in Zukunft keine Sessions benutzt werden (e.g. die vielen Server-interne Dinge die keine Client-Interaktion haben)!
DB Transactions spanning multiple Server calls
TODO
BackgroundworkManager Object (geringe Prioritaet)
- Globales Objekt auf Clientseite um 'delayed data loading' komplett in Hintergrund-Threads abwickeln zu koennen (e.g. im Partner Edit Screen: Daten fuer 'Addresses'- und 'Subscriptions'-Tabs immer im Hintergrund laden, auch wenn zu allererst ein anderes Tab [e.g. 'Partner Types'] vom User geoeffnet wurde)
- Hat einen internen Thread-Pool von max. eg. 3 'Worker Threads', die von beliebigen Stellen im Client fuer Hintergrundaufgaben herangezogen werden koennen, wenn diese Hintergrundaufgaben nicht innerhalb einer bestimmten Zeit ausgefuehrt werden muessen
- Wuerden mehr Worker Threads angefordert als im internen 'Thread Pool' abgearbeitet werden koennen, wuerden diese Anfragen in eine Queue gestellt. Diese 'gequeueten' Anfragen wuerden nach und nach in den 'Thread Pool' rutschen und anschliessend abgearbeitet werden, sobald mindestens einer der bisher laufenden Threads im 'Thread Pool' beendet wurde.
- Aufpassen: Synchroniserung des Datenladens so absichern dass sicher keine (evtl. veraenderten) lokalen Daten ueberschrieben werden koennen, egal wie lange der asynchrone Servercall dauert (der Benutzer koennte inzwischen lokale Daten geaendert haben die mit dem Rueckgabewert des Servercalls ueberschrieben werden koennten)!!!
- Hat einen internen Thread-Pool von max. eg. 3 'Worker Threads', die von beliebigen Stellen im Client fuer Hintergrundaufgaben herangezogen werden koennen, wenn diese Hintergrundaufgaben nicht innerhalb einer bestimmten Zeit ausgefuehrt werden muessen
Weitere Diskussionspunkte
?????