Laden...

OR-Mapper: Defizite beim Databinding?

Erstellt von ErfinderDesRades vor 14 Jahren Letzter Beitrag vor 14 Jahren 3.118 Views
ErfinderDesRades Themenstarter:in
5.299 Beiträge seit 2008
vor 14 Jahren
OR-Mapper: Defizite beim Databinding?

verwendetes Datenbanksystem: <ms sql 2008Express>

Hallo!

Ich wurstel mich grad bischen in den Linq2Sql-Datacontext ein, und finde, dasser vom Databinding her ziemlich hinter olle Dataset hinterherhinkt.

Also an Dataset gebundene Datagridviews zeigen immer konsistente Views an, während beim DataContext im einen View Datensätze noch zu sehen sind, die im anderen gelöscht sind.

Ist das normal?
Muss das so?
Funktioniert das beim Entity-Framework oder nHibernate besser?

Ich hab maln Sample gebastelt, für den direkten Vergleich.

Der frühe Apfel fängt den Wurm.

6.911 Beiträge seit 2009
vor 14 Jahren

Hallo,

Also an Dataset gebundene Datagridviews zeigen immer konsistente Views an, während beim DataContext im einen View Datensätze noch zu sehen sind, die im anderen gelöscht sind.

Ist das normal?
Muss das so?

Dieses Verhalten ist "as designed". Wird im DGV ein Datensatz gelöscht so wird dieser nicht aus dem DataContext entfernt sondern dort auf zum Löschen markiert er verbleibt aber im DataContext - wird für das Changetracking verwendet.
Unter Data Binding (LINQ 2 SQL) gibt Mircosoft an:

If an entity is bound in two separate grids (for example, one master and another detail), a Delete in the master grid is not propagated to the detail grid.

Funktioniert das beim Entity-Framework oder nHibernate besser?

Weiß ich nicht.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

I
302 Beiträge seit 2008
vor 14 Jahren

nein beim entity ist das genauso. kannst natürlich immer savechanges machen.

ErfinderDesRades Themenstarter:in
5.299 Beiträge seit 2008
vor 14 Jahren

Ein SaveChanges (DataContext: SubmitChanges) korrigiert ja noch nicht die Anzeige meines 2. Views. Dazu müsste ich SubmitChanges machen, und dann den ganzen Sermon neu laden - das ist doch Irrsinn!

@gfoidl: jetzt habichmir einen WebCast zu SQLServer-Change Tracking angeguckt - das hat aber nix mittm DataContext zu tun, scheint mir.

Und: Die Daten würden ebensogut im DataContext verbleiben, wenn der sich die Mühe machen würde, auch den anderen View von den Änderungen zu unterrichten.
Ich habn MordsWorkaround gebastelt, wo die beteiligten BindingSources sich gegenseitig unterrichten, und so die Views synchronisieren. Also was im einen Grid gelöscht wird, wird auch im anderen gelöscht.
Wennichda DataContext.Getchanges mache, kriege ich die Changes ebenso korrekt wie von den unsynchronisierten Views.

Die Frage bleibt offen: Dataset hats gekonnt, warum könnens OR-Mapper nicht mehr?

Der frühe Apfel fängt den Wurm.

3.728 Beiträge seit 2005
vor 14 Jahren
OR-Mapper

Hallo ErfinderDesRades,

das ist so, weil es einfach normale "dumme" Objekte sind. Schau mal hier: das ist so, weil POCOS (plain old C# objects) einfach grundsätzlich nur wissen, was ihn ihren Feldvariablen steht.

http://yellow-rainbird.de/blogs/rainbird/archive/2009/01/09/habe-sehnsucht-nach-dem-rowstate.aspx

Das Problem ist, dass man den Objekten die fehlende Funktionalität wieder beibringen müsste. Dann wäre man aber implizit wieder beim "fetten" DataSet. Die Frage ist also, ob OR-Mapper überhaupt der richtige Weg sind? Ich meine mittlerweile nein. Warum nicht einfach typisierte DataSets verwenden. Die können das alles schon. Man muss nicht alles neue annehmen, nur weil es neu ist und überall angepriesen wird. Wenn es niemand einsetzt, verschwindet es wieder vom Markt. Ganz von allein.

6.911 Beiträge seit 2009
vor 14 Jahren

@gfoidl: jetzt habichmir einen WebCast zu SQLServer-Change Tracking angeguckt - das hat aber nix mittm DataContext zu tun, scheint mir.

Der DataContext überwacht die Änderung der Entitäten die zu dem DataContext gehören. Wird zB im Beispiel eine Instanz von Category geändert die vorher mittels DataContext von der Datenbank geholt wurde so vermerkt der DataContext dies in seinem Cache. Wird dann SubmitChanges(...) aufgerufen so wird der "Objectgraph" abgearbeitet und alle Änderungen werden "in die Datenbank übergeführt". Anführungszeichen deshalb weil es auf die Einstellungen für den ConflictMode ankommt.
Wird eine Enität gelöscht so wird die Instanz nicht aus dem DataContext entfernt sonder lediglich mit "zum Löschen" markiert. Deshalb funktioniert dein Datenbindungbeispiel nicht so wie du dir es erwartest - der Datensatz ist noch vorhanden und wird deshalb auch angezeigt.

Ein DataContext sollte "kurzlebig" sein (wobei kurzlebig je nach Anforderung unterschiedlich ausfallen kann) und bei Änderungen wie zB Löschen neu erstellt werden damit die Daten mit jener der Datenbank synchron sind.

Treten hingegen Änderungen auf der Datenbankseite auf so bekommt der DataContext davon nichts mit. Erst bei SubmitChanges. Dies kann zu Konflikten führen wenn "alte" Daten im DataContext vorhanden sind. Dazu müssen Einstellungen bezüglcih ConflictMode getroffen werden.

Ich habn MordsWorkaround gebastelt, wo die beteiligten BindingSources sich gegenseitig unterrichten, und so die Views synchronisieren. Also was im einen Grid gelöscht wird, wird auch im anderen gelöscht.

So aufwändig muss der Workaraound gar nicht sein. Schau mal:


using System.ComponentModel;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
	public partial class Form1 : Form
	{
		private DataClasses1DataContext _db = new DataClasses1DataContext();

		public Form1()
		{
			InitializeComponent();

			categoryBindingSource.DataSource = _db.Category;
			productBindingSource1.DataSource = _db.Product;

			categoryBindingSource.ListChanged +=
				(sender, e) =>
				{
					if (e.ListChangedType == ListChangedType.ItemDeleted)
					{
						_db.SubmitChanges();
						_db = new DataClasses1DataContext();
						categoryBindingSource.DataSource = _db.Category;
						productBindingSource1.DataSource = _db.Product;
					}
				};
		}
	}
}

Dabei wird nur die BindingSource auf Löschen "überwacht" und dann die Datenbank aktualisiert und ein neuer DataContext erstellt.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

ErfinderDesRades Themenstarter:in
5.299 Beiträge seit 2008
vor 14 Jahren

nojaa - das habich im vorigen Post frecherweise als "irrsinn" bezeichnet - tschuldigung, istata! 😉
Jedenfalls würde ich was ressourcenschonenderes erwarten, als für jede gelöschte Zeile den gesamten DataContext auszutauschen, alle angezeigten Daten neu von der DB holen und alle am DataContext angeschlossene Views neu zu befüllen.

Ich hätt ja auch gedacht, an einen DataContext könnten sich u.U. auch mehrere Forms anstöpseln und sowas - da wären die bindingSources auch nicht mehr so ohniweiteres zum umstöpseln verfügbar.

@Rainbird:
thx, irgendwie beruhigend, dass du olle Datasets nicht so ohneweiteres in der Gruft verschwinden lässt - ich komme mir nämlich vor wie Hinterwäldler, weil ich mit denen eiglich immer recht gut zurande komme.

Aber das mittm Databinding, das scheint mir prinzipiell lösbar, auch mit dummen Objekten.
Iwie müssten Linq.Table bzw. EntitySet nur ein ListChanged feuern mit ListChangeType.ItemDeleted.
Eine geeignete IBindingList steht ja eiglich dahinter.

Der frühe Apfel fängt den Wurm.

3.728 Beiträge seit 2005
vor 14 Jahren
Zukunftsmusik

Mit dem .NET Framework 4.0 soll es etwas besser werden im Entity Framework. Da ist dann von Selftracking Entities die Rede. Aber ganz ehrlich: Das ist DataSet-Funktionalität durch Hintertürchen über hässliche draufgepfofte Workarounds, die eigentlich nicht zum Konzept passen. Was ist an DataSets/DataTables angeblich falsch? Warum wollen so viele Leute auf biegen und brechen relationale Daten in herkömmliche Objekte packen?

Wenn die Java-Jungs das machen, versteh ich das, die haben keine komfortable Datenzugriffs-API wie ADO.NET (JDBC erinnert eher an Classic-ADO). Aber im .NET Framework besteht dafür eigentlich keine Notwendigkeit. Genausowenig, wie Java-Portierungen fürs Logging in .NET zu verwenden (wir haben in System.Diagnostics exzellentes Logging), oder in C# mit dem Spring-Framework zu hantieren.

1.564 Beiträge seit 2007
vor 14 Jahren

@ErfinderDesRades:
Ich würde LINQ2SQL nicht so verteufeln 😉. Wie gfoidl schon geschrieben hat, das Konzept ist halt ein anderes. Trenne dich hier von dem Daten-Monoliten im Hintergrund dann dürfte es funktionieren. Ich würde mal nach einem Tutorial suchen welches das Konzept erklärt.

@Rainbird:
"Die Frage ist also, ob OR-Mapper überhaupt der richtige Weg sind? Ich meine mittlerweile nein."
Kommt, meiner Meinung nach, drauf an.

Für schlanke Projekte sind typisierte DataSets oder auch LINQ2SQL bestimmt oft der beste Weg. Die beiden sind sich nämlich sehr ähnlich. Beide stellen ein 1:1 Mapping zwischen Datenbank und Businessschicht dar.

In großen Projekten ist ein 1:1 Mapping zwischen Datenbank und Businessschicht schnell ein echtes Problem. Man nimmt hier auf beiden Seiten die Möglichkeit gekapselt zu optimieren ohne immer gleich die gesamte Welt umzubauen. Hier sind O/R-Mapper wie nHibernate oder Entity Framework wesentlich flexibler da sie die beiden Ebenen von einander trennen.

Blog: Things about Software Architecture, .NET development and SQL Server
Twitter
Google+

Je mehr ich weiß, desto mehr weiß ich was ich noch nicht weiß.

3.728 Beiträge seit 2005
vor 14 Jahren
Mapping

Das kannst Du doch aber auch mit DataSets haben. DataSets können eine völlig andere Struktur haben, als die Datenbank. ADO.NET Datenadapter haben auch ein eingebautes Mapping, damit Felder im DataSet nicht heißen müssen, wie in der Datenbank. Man muss ja auch keine TableAdapter verwenden. DataSets sind ja nur Datencontainer, die meine Daten zwischen den Schichten in- und hertransportieren. Man kann ja auch mit dem Entity Framework ein Datenmodell aufbauen und auf dieses über den ESQL-ADO.NET Provider zugreifen und über ESQL seine DataSets füllen. Das Problem ist einfach, dass die platten Objekte nicht den nötigen Komfort haben (Vor allem wenn man Detachen und Attachen muss, weil man über Prozessgrenzen hinweg arbeitet).

Außerdem kann ich in DataSets (auch typisierte) jederzeit zur Laufzeit dynamisch neue Tabellen und Spalten hinzufügen, um sie z.B. temporär mit Zusätzlichen Daten für die Anzeige anzureichern. Auch brechnete Felder (z.B. automatisch die MWST ausrechnen, sobald sich die Positionsmenge ändert, sind kein Problem und können bei Bedarf zur Laufzeit angefügt werden, ohne das fest im typisierten DataSet einzubauen. Objekte sind da viel starrer.

1.564 Beiträge seit 2007
vor 14 Jahren

Das kannst Du doch aber auch mit DataSets haben. DataSets können eine völlig andere Struktur haben, als die Datenbank. ADO.NET Datenadapter haben auch ein eingebautes Mapping, damit Felder im DataSet nicht heißen müssen, wie in der Datenbank. Man muss ja auch keine TableAdapter verwenden. DataSets sind ja nur Datencontainer, die meine Daten zwischen den Schichten in- und hertransportieren.

Ich sehe aber eben diese 1:1 Beziehung zwischen Datenbank und Businesslayer eigentlich als eien ziemlich große Stärke von typisierten DataSets. Hiermit stechen sie in kleinen Projekten große Frameworks wie EF oder nH eventuell sogart aus. Es fällt nämlich schlicht das - nicht ganz unaufwändige - Mapping zwischen Datenbank und Businessschicht weg und man kann wesentlich schneller zum Ziel kommen.

Natürlich kann ich ein DataSet auch komplett ohne Bezug zur Datenbank typisieren dann habe ich aber nicht mehr viel mehr als der normale Klassendesigner bietet und eine mehr oder weniger korrekt implementierte Memento Funktionalität. Wenn ich nicht die Datenbankstruktur abbilde sehe ich DataSets nur selten als sinnvoll.
Erinnert mich irgendwie an das Sprichwort "Ich habe einen Hammer, also ist alles andere ein Nagel"
(Kenn' ich zwar nur aus dem Englischen, aber gefällt mir) 😁

Man kann ja auch mit dem Entity Framework ein Datenmodell aufbauen und auf dieses über den ESQL-ADO.NET Provider zugreifen und über ESQL seine DataSets füllen.

Bin ich kein Freund von; weder ESQL noch von den RowFilter/Select/Whatever von DataSets/DataTables. Ich bin grundsätzlich ein Gegner von Code in Strings. Habe selbst zu viel schlechte Erfahrung in größeren Teams damit gemacht.
Achtung: Komplett subjektive Meinung ohne objektive Intensionen

Das Problem ist einfach, dass die platten Objekte nicht den nötigen Komfort haben

Stimmt schon, dass DataTable und DataRow (das DataSet ist ja primär der Container) einige recht schicke Features bieten. Leider ist die DataTable so mit Funktionalität überladen dass nur sehr wenige wirklich alle Möglichkeiten nutzen bzw. einige der Methoden auch fehlerhaft implementiert sind.

(Vor allem wenn man Detachen und Attachen muss, weil man über Prozessgrenzen hinweg arbeitet).

Was meinst du mit "über Detachen und Attachen über Prozessgrenzen hinaus"?

Außerdem kann ich in DataSets (auch typisierte) jederzeit zur Laufzeit dynamisch neue Tabellen und Spalten hinzufügen, um sie z.B. temporär mit Zusätzlichen Daten für die Anzeige anzureichern. Auch brechnete Felder (z.B. automatisch die MWST ausrechnen, sobald sich die Positionsmenge ändert, sind kein Problem und können bei Bedarf zur Laufzeit angefügt werden, ohne das fest im typisierten DataSet einzubauen. Objekte sind da viel starrer.

Gutes Argument, kann man aber alles recht einfach mit so ziemlich jedem Objekt machen wenn INotifyPropertyChanged implementiert ist und man einen TypeDescriptor implementiert.

Gute Nacht
Flo

Blog: Things about Software Architecture, .NET development and SQL Server
Twitter
Google+

Je mehr ich weiß, desto mehr weiß ich was ich noch nicht weiß.

F
10.010 Beiträge seit 2004
vor 14 Jahren

@Florian Reischl:
Rainbird arbeitet fast ausschliesslich mit Appservern, und da ist der Übergang
also der Transfer der Daten von einer AppDomain in eine andere (auch über PC grenzen hinweg ) nötig.

Aber das ist nicht etwas, was der überwiegende Teil der Entwickler braucht .

Und wer sich wie ErfinderDesRades nicht an echte OOP halten will (siehe z.b. kommentar zu globaler Connection in anderen Threads),
der findet natürlich die komplett freie und untypisierte herangehensweise von DataSet und co prima.
Und dann sind natürlich andere herangehensweisen von anderen Systemen nur schwer anzunehmen, denn das würde ja ein Umdenken benötigen.

Aber wer dann mal in grösseren Projekten gearbeitet hat ( und SmartClients können
grösser werden ohne eine Appserver zu benötigen ), der weiss, das eben Code in Strings, und nichts anderes ist das dann, zu massiven Problemen führt.

1.564 Beiträge seit 2007
vor 14 Jahren

Rainbird arbeitet fast ausschliesslich mit Appservern, und da ist der Übergang
also der Transfer der Daten von einer AppDomain in eine andere (auch über PC grenzen hinweg ) nötig.

Disclaimer: Ich weiß jetzt nicht genau welche der bestehenden Möglichkeiten (MarshalByValue, IXmlSerializable, ISerializable, ???) der DataTable hier verwendet wird also kann dieser Post jetzt komplett in die falsche Richtung gehen.

Eben diese ganzen Funktionalitäten der DataTable sehe ich als wirklich großes Problem dieses Objekts (und seinen Geschwistern). Durch ihren Namen und den Namespace sagt die DataTable aus dass sie sich um die Datenanbindung kümmert. Nebenbei kann sie aber noch als Business-Layer Basis, zum Serialisieren nach XML, Serialisieren für Remoting, DataBinding kümmern. Irgendwie ist das Objekt aber als "Eierlegende Wollmilch Sau" implementiert worden und das zerstört - in meinen Augen - die Übersicht. Alle diese Funktionalitäten lassen sich recht einfach über Adapter oder ein paar Attribute realisieren, so wäre das Objekt wesentlich übersichtlicher geblieben.

Blog: Things about Software Architecture, .NET development and SQL Server
Twitter
Google+

Je mehr ich weiß, desto mehr weiß ich was ich noch nicht weiß.

ErfinderDesRades Themenstarter:in
5.299 Beiträge seit 2008
vor 14 Jahren

Und wer sich wie ErfinderDesRades nicht an echte OOP halten will (siehe z.b. kommentar zu globaler Connection in anderen Threads),
der findet natürlich die komplett freie und untypisierte herangehensweise von DataSet und co prima.

Hmm, hmm. Das kannichnatürlich ühaupt nicht so stehen lassen. Leider gehörts hier aber auch nicht zum thema.

Ist erstmal ne Unterstellung, dassichmich nicht an echte OOP halten wolle (was immer das sein mag).

Dann müsstest du noch nachweisen, warum sich meine Ansichten zu globalen Connections nicht mit "echter OOP" vertragen.

Und selbst wenn dir das gelänge, müsstest du mir immer noch erklären, warum diese Ansichten suboptimal sind, denn nur mit einer Richtlinie übereinzustimmen, ist für mich tatsächlich kein Argument.
Nichts gegen Richtlinien - 's gibtn Haufen Pattern, Prinzipien und Richtlinien, die ich voll vertrete (was ich für OOP halte gehört übrigens dazu). Aber in jedem einzelnen Fall weiß ich auch _warum _ich eine Richtlinie gut finde.

Bitte in den entsprechenden Threads.

Und wenn jemand mit untypisierten Datasets ankommt, binnich doch eiglich immer der erste, der darauf antwortet, dass sowas keine Basis für irgendwas ist.

Der frühe Apfel fängt den Wurm.

1.564 Beiträge seit 2007
vor 14 Jahren

Bitte in den entsprechenden Threads.

Hast du hierzu einen Link?

Blog: Things about Software Architecture, .NET development and SQL Server
Twitter
Google+

Je mehr ich weiß, desto mehr weiß ich was ich noch nicht weiß.

ErfinderDesRades Themenstarter:in
5.299 Beiträge seit 2008
vor 14 Jahren

hab ihn jetzt wieder gefunden. Dataset / DataAdapter - Probleme beim Speichern
Der eignet sich aber auch nicht für diese Diskussion.

Ich mach maln neuen auf.

Der frühe Apfel fängt den Wurm.

ErfinderDesRades Themenstarter:in
5.299 Beiträge seit 2008
vor 14 Jahren

Der frühe Apfel fängt den Wurm.