Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Linq2Sql: Multiuser und mehre DataContexte
binaryblob
myCSharp.de - Member



Dabei seit:
Beiträge: 36

Themenstarter:

Linq2Sql: Multiuser und mehre DataContexte

beantworten | zitieren | melden

Hallo zusammen

Habe eine Art Kalender Programm (wie Outlook) in das mehrere Benutzer gleichzeitig Daten schreiben und lesen können.

Benutzt als DB, SQL-Server über Netzwerk mit LINQ.

Ich benutze momentan 1 DataContext in meiner Anwendung, der also einmal erstellt wird und dann alles über denn gemacht wird. Bis das Programm wieder geschlossen wird.


Dazu mehrere Fragen:
1. Ist das gut 1 DataContext, oder sollte ich für jede Aktione einen neuen instanzieren?

Habe relativ viele solche Funktionen

        internal static void Check(Season season)
        {

            foreach (Season ses in DatabaseContext.Season)
            {
                if (ses == season)
                {
                    SetText("FOUND");
                }
            }
         }

Wenn jetzt aber das übergebene Season nicht vom gleiche DataContext ist, wird es nicht gefunden oder ich müsste noch Attach machen... Irgendwie beschissen! Oder müsste ich direkt den Primarykey checken und nicht die Objekte vergleichen? Irgendwie sehe ich das noch nicht ganz...

2. Wenn Änderungen von einem anderen User gemacht wurde, müssen das natürlich die anderen Programme mitkreigen, wie kann ich am einfachsten DataContexte Refreshen?

Danke für die Auskunft!
private Nachricht | Beiträge des Benutzers
gfoidl
myCSharp.de - Team

Avatar #avatar-2894.jpg


Dabei seit:
Beiträge: 7572
Herkunft: Waidring

beantworten | zitieren | melden

Hallo binaryblob,

ein DataContext sollte solange leben wie eine "Arbeitseinheit" dauert (engl: Unit of Work). Dadurch ist auch (mehr oder weniger) sichergestellt dass die Daten im Datacontext nicht schal werden.

Für die restliche Anwendugn würde ich auch nicht mit den vom Designer generierten Klassen arbeiten, sondern mit eigenen POCOs. Dann fällt hier die Attach-Problematik so weg, allerdings müssen die Eigenschaften umkopiert werden.

Linq2Sql unterstützt aber auch POCOs. Suche mal danach wenn dir dieser Weg genehm vorkommt. Kurz: mit SQLMetal.exe können diese generiert werden, oder selbst das Xml-Mapping erstellt werden.
Zitat
Ist das gut 1 DataContext, oder sollte ich für jede Aktione einen neuen instanzieren?
Wie oben erwähnt für jede Arbeitseinheit. Das muss nicht zwangsläufig eine einzelne Aktion sein. ZB Lesen, Ändern und zurückschcreiben ist eine Arbeitseinheit.

Das 2. erschlägst du damit auch.



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!"
private Nachricht | Beiträge des Benutzers
binaryblob
myCSharp.de - Member



Dabei seit:
Beiträge: 36

Themenstarter:

beantworten | zitieren | melden

Hallo Gü

Ok, verstehe noch nicht ganz was du mit POCOs meinst, kann du mir da kurz ein vertändliches Bsp. geben?

Danke!
private Nachricht | Beiträge des Benutzers
gfoidl
myCSharp.de - Team

Avatar #avatar-2894.jpg


Dabei seit:
Beiträge: 7572
Herkunft: Waidring

beantworten | zitieren | melden

Hallo binaryblob,

wenn du mit dem Linq2Sql-Designer eine Tabelle von der Datenbank reinziehst ertellt dieser ein Klasse, zB


[TableMapping(....)]
public partial class Kunde : xxx
{
    // haufen Code
}
in der alles mögliche mitgespeichert wird das Linq2Sql zum funktionieren braucht. Damit sind diese Klasse voll abhängig von Linq2Sql (-> persistance aware) und das ist oft nicht praktisch. Dazu gleich mehr.

Wenn die Klasse aber ein POCO ist, also


public class Kunde // : IDataErrorInfo, INotifyPropertyChanged zB
{

}
dann ist diese Klasse unabhängig von einer Speichertechnologie wie Linq2Sql (-> persintance ignorant). Diese Klasse kann somit in jeder Anwendung verwendet werden, serialisiert werden (und somit zB per WCF übertragen), etc. Sie ist auch lösgelöst von einem DataContext und unterstützt somit viel mehr eine mehrschichtige Architektur wie erstere. Diese Klassen verwendest du dann auch in den UI-Schichten der Anwendung.

Schau dir mal das Beispiel in [erledigt] Entity Framework Abfrage mit Beziehungen an. Das gilt für Linq2Sql genauso wie für das Ado.net EF für das ich es erstellt habe.

Beim Speichern/Aktualisieren von DB-Einträgen gehtst du den selben Weg. Das Problem mit dem Attachen ist nicht mehr vorhanden. Auch kann zB ein IEnumerable<T> außerhalb des DataContext zugegriffen werden ohne dass der Fehler "auf das Objekt kann nicht ...." kommt.

Being Ignorant with LINQ to SQL ist ein etwas längerer Artikel der das ausführlicher beschreibt.


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!"
private Nachricht | Beiträge des Benutzers
binaryblob
myCSharp.de - Member



Dabei seit:
Beiträge: 36

Themenstarter:

beantworten | zitieren | melden

Hallo Gü,

Danke für die Antwort!

Ich generiere meine DB direkt auf VS mit CreateDatabase().

Jetzt wenn ich das richtig verstehe, müsste ich für jede Entität sozusagen eine zusätzliche Klasse machen.

Aber was ich nicht sehe, schlussendlich will ich ja nicht z.B. auf WCF umstellen, sonder weitherhin die Daten über InsertOnSubmit() in die DB füllen.

Aber da bin ich doch schlussendlich wieder gleichweit, wie am Anfang oder kapiere ich den Ansatz nicht??

Weiter ist das Problem, es geht hier um eine DB mit etwa 20 Tabellen, also etwas ein grober Aufwand, für ein Problem, das doch eigentlich einfacher lösbar sein sollte?!!

Danke
private Nachricht | Beiträge des Benutzers
Ahrimaan
myCSharp.de - Member



Dabei seit:
Beiträge: 363
Herkunft: Thorn

beantworten | zitieren | melden

Hi,

ja sicher kannst du das ganze einfacher lösen, ich denke aber es soll sich ein gewisser Lerneffekt einstellen :
Saubere Trennung von Schichten und ein gewisses Maß an sauberem Code.

Ich denke, wenn du dich an gfoidl Tipps hälst, kannst du sauberen Code produzieren.

Grüße
private Nachricht | Beiträge des Benutzers
binaryblob
myCSharp.de - Member



Dabei seit:
Beiträge: 36

Themenstarter:

beantworten | zitieren | melden

Ja, allerdings hat man ja mit den Linq Klassen schon eine gute Trennung, darum finde ich das ganze etwas umständlich noch mal zu machen...
private Nachricht | Beiträge des Benutzers
gfoidl
myCSharp.de - Team

Avatar #avatar-2894.jpg


Dabei seit:
Beiträge: 7572
Herkunft: Waidring

beantworten | zitieren | melden

Hallo binaryblob,

es ist so wie Ahrimaan geschrieben hat. Von WCF, udgl. war die Rede.
Zitat
mit den Linq Klassen schon eine gute Trennung
Eben nicht. Wenn du eine Instanz dieser Klasse in der UI anzeigst dann ist das ganze Linq2Sql-Zeugs auch dabei, da eben diese Klasse von den ganzen Linq-Basisklassen erben und mit Attribute überseht sind. Zum anderen wenn die Instanz vom DataContext getrennt ist dann gibt es Probleme. Daher wird oft - und fälschlicherweise - der DataContext für immer offen gehalten und somit tritt genau eines der Probleme auf die du eingangs beschrieben hast.
Zitat
Jetzt wenn ich das richtig verstehe, müsste ich für jede Entität sozusagen eine zusätzliche Klasse machen.
Nein.
Zitat
es geht hier um eine DB mit etwa 20 Tabellen, also etwas ein grober Aufwand,
Ich gehen davon aus dass diese Tabellen nicht 1:1 so in der UI angezeigt werden sollen, sondern entsprechend aufbereitet und spezialisiert. Da dieser Schritt sowieso notwendig ist sind nur diese "spezialisierten" Klassen zu erstellen. ZB wenn in der DB eine Tabelle Produkt und eine Tabelle Hersteller normalisiert ist dann hat Produkt einen Fremdschlüssel zum Hersteller. In der UI wird aber wahrscheinlich nur eine "Kombination" aus beiden Tabellen angezeit, so dass die zu erstellende Klasse etwas wie folgt aussehen kann


public class Produkt : IDataErrrorInfo
{
    public int ProduktId {get; set;}
    public string Name {get; set;}
    public string Hersteller {get; set;}
}
und im Repository entsprechend


public class ProduktRepository : IProduktRepository, IDisposable
{
    private readonly DataContext _db;

    public IList<Produkt> HoleAlleProdukte()
    {
        return _db.Produkte    // die aus dem Mapping von Linq2Sql
            .Select(p => new Produkt{ProduktId = p.Id, Name = p.ProduktName, Hersteller = p.Herteller.Name}
            .ToList();
    }

    public IList<Produkt> HoleAlleProdukte(int herstellerId)
    {
        returns _db.Produkte
            .Where(p => p.Hersteller.Id == herstellerId)
            .Select(p => // wie oben)
            .ToList();
    }

    // usw.
}
Zitat
darum finde ich das ganze etwas umständlich noch mal zu machen..
Umständlicher ist relativ. Wenn dafür keine Problem auftreten ist es weniger umständlicher als irgendwelche Kunstegriffe die es anderswertig die Probleme zu beheben versuchen ;-)

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!"
private Nachricht | Beiträge des Benutzers
binaryblob
myCSharp.de - Member



Dabei seit:
Beiträge: 36

Themenstarter:

beantworten | zitieren | melden

Ok, werde das mal anschauen!

Danke euch für die Hilfe!

Gruss blöb
private Nachricht | Beiträge des Benutzers