Laden...

[erledigt] Entity Framework Abfrage mit Beziehungen

Erstellt von Brain-Patter vor 12 Jahren Letzter Beitrag vor 12 Jahren 2.937 Views
B
Brain-Patter Themenstarter:in
12 Beiträge seit 2011
vor 12 Jahren
[erledigt] Entity Framework Abfrage mit Beziehungen

verwendetes Datenbanksystem: SQL-Server 2008

Hallo zusammen,

ich arbeite mich gerade in das Entity Framework ein und komme beim folgenden Fall einfach nicht dahinter wie es hier gelöst wird. Vielleicht noch kurz zur Erklärung, bis jetzt habe ich nur mit C++ und klassischem SQL gearbeitet. Momentan versuche ich mich in C# + Entity Framework einzuarbeiten.

Und nun zur Aufgabe:

Es gibt im System eine Tabelle „Kennzeichen“, die alle möglichen Wertelisten für die im Programm verwendeten ComboBoxen beinhaltet. Hier einige Beispiele:

PK_Kennzeichen |FK_Kennzeichen_Kopf |Bezeichnung
1..............|1...................|Lieferung
2..............|1...................|Rechnung
3..............|1...................|Post
4..............|2...................|Herr
5..............|2...................|Frau
6..............|2...................|Eheleute

Soll nun eine ComboBox mit der Anrede befüllt werden würde das SQL wie folgt aussehen:

Select bezeichnung from Kennzeichen where FK_Kennzeichen_Kopf = 2

Das ganze per Entität im Framework darzustellen ist auch kein Problem.

Wo ich nun nicht weiter komme ist folgende Tabellenkonstellation/Abfrage:

Tabelle mit Kunden --> ref auf Kennzeichen:
PK_Kunde |KZ_Anrede |Name......|KZ_Adresstyp
1........|4.........|Mustermann|2
2........|5.........|Musterfrau|2

Möchte ich nun die Tabelle Kunden mit den Kennzeichen verknüpfen, würde ich das SQL-Statement momentan folgender Maßen ausbilden:

    select kunde.PK_Kunde,
	   kz1.Bezeichnung as KZ_Anrede,
	   kunde.Name,
	   kz2.Bezeichnung as KZ_Adresstyp
      from Konfiguration.Kennzeichen kz1,
	   Konfiguration.Kennzeichen kz2,
	   dbo.Kunde kunde
     where kz1.PK_Kennzeichen = kunde.KZ_Adresstyp
           and kz2.PK_Kennzeichen = kunde.KZ_anrede    

Das Ergebniss für die erste Zeile in der Kunden Tabelle wäre nun:

PK_Kunde |KZ_Anrede |Name......|KZ_Adresstyp
1........|Herr......|Mustermann|Rechnung

Wie kann ich so etwas nun mit dem Entity Framework abbilden? Muss ich hier einen ganz anderen Denkansatz gehen, oder lässt sich das ganze mit Linq to Entities lösen, wenn ja wie?

Schon mal vielen Dank und viele Grüße

Braini

6.911 Beiträge seit 2009
vor 12 Jahren

Hallo Brain-Patter,

das Ergebnis der Abfrage ist eine Projektion auf einen Typ der nicht existiert. Hierzu wurde mit Linq das Konzept von anonymen Typen eingeführt mit den die Abfrage trotzdem - oder gerade deshalb - umgesetzt werden kann. Suche mal nach diesem Stichwort dann wird die klar wie es geht.


var query = from .... select new { Hier die Eigenschaften des anonymen Typ = Select vom SQL }

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!"

B
Brain-Patter Themenstarter:in
12 Beiträge seit 2011
vor 12 Jahren

Hallo gfoidl,

sorry das ich mich erst so spät wieder melde - ich bin leider nicht schneller dazu gekommen.

Erstmal vielen Dank für deine schnelle Hilfe und den Tipp in die richtige Richtung.

Ich habe das ganze nun so gelöst:

        private void simpleButton1_Click(object sender, EventArgs e)
        {
            KundenEntities context = new KundenEntities();

            var query_Kunde = from kunden in context.Kunde
                            join kennzeichen_KZ_Adresstyp in context.Kennzeichen on kunden.KZ_Adresstyp equals kennzeichen_KZ_Adresstyp.PK_Kennzeichen into Sub
                            join kennzeichen_KZ_Anrede in context.Kennzeichen on kunden.KZ_Anrede equals kennzeichen_KZ_Anrede.PK_Kennzeichen into Sub2
                            from Result_KZ_Adresstyp in Sub.DefaultIfEmpty()
                            from Result_KZ_Anrede in Sub2.DefaultIfEmpty()
                            select new 
                            { 
                                PK_Kunde = kunden.PK_Kunde, 
                                KZ_Anrede = Result_KZ_Anrede == null ? "leer" : Result_KZ_Anrede.Bezeichnung,
                                Name = kunden.Name,
                                KZ_Adresstyp = Result_KZ_Adresstyp == null ? "leer" : Result_KZ_Adresstyp.Bezeichnung
                             };

            BindingSource bs = new BindingSource();
            bs.DataSource = query_Kunde;
            gridControl1.DataSource = bs;
        }

Das Ergebnis was ich erhalte ist korrekt, nur kommt mir das alles syntaktisch falsch vor.

Ich würde ich mich freuen, wenn du kurz drüber gucken könntest und mir ggf.. noch den einen oder anderen Tipp geben könntest.

6.911 Beiträge seit 2009
vor 12 Jahren

Hallo Brain-Patter,

jetzt sehe ich erst richtig worum es geht 😃

Existieren in der DB Fremdschlüsselbeziehungen zwischen den Tabellen? Wenn ja dann ist in der Lin-Query kein explizites Join notwendig, es reicht auf die Eigenschaft zuzugreifen. ZB


from kunde in context.Kunden  // kunde ist besser als kunden denn es ist nur 1, hingegen context.Kunden denn es sind alle
select new
{
    PK_Kunde  = kunde.PK_Kunde,
    KZ_Anrede = kunde.KZ_Anrede.Bezeichnung
};

Die Bezeichnungen würde ich sowieso anders wählen. Die Präfix stören mMn und sind nur unnötiges Rauschen im Code. Siehe Guidelines for Names - ist zwar für C#, aber wenn EF verwendet wird gilt das auch für die DB 😉

Bei deinem gezeigten Code vermischt du UI und Logik. Das ist nicht gut. Warum? Dazu findest du genügend Info über die Forensuche, etc.
Daher würde ich das Trennen. Ganz grob so:


public class MeineForm : Form
{
    private readonly KundeRepository _kundenRepo;

    public MeineForm()
    {
        _kundenRepo = new KundenRepository();  // besser wäre Übergabe im Ctor durch DI, aber erstmal reicht das so.
    }

    private void btnLadeKunden_Click(object sender, EventArgs e)
    {
        BindingSource bs = new BindingSource();
        bs.DataSource = _kundenRepo.GetKunden();
        dgvKunden.DataSource = bs;
    }
}


public class KundenRepository : IDisposable // ev. IKundenRepository -> besser testbar, aber fürs erste reicht es
{
    private readonly KundenEntities _db = new KundenEntities();

    public IList<MeinKundenEintrag> GetKunden()
    {
        // hier die Query
        var query = from kunde in _db.Kunden
                    select new MeinKundenEintrag
                    {
                         Name = kunde.Name,
                         Anrede = kunde.Anreden.Bezeichnung
                         // usw.
                    };  

        return query.ToList();
    }

    public void Dispose()
    {
        _db.Dispose();    // hier nur schematisch -> bitte das Dispose-Pattern korrekt umsetzen.
    }
}

Bzgl. Dispose siehe Dispose implementieren und verwenden (IDisposable)


public class MeinKundenEintrag
{
    // hier die Eigenschaften die in der Query (oben) gesetzt werden. 
    // Somit wird kein anonymer Typ mehr verwendet sondern ein benannter. Das hat unterm Strich Vorteile

    public string Name {get;set;}
    public string Anrede {get;set;}
    // usw.
}

Wie du also siehst wurde alles schön in Klassen ausgelagert und jede Klasse macht nur das wofür sie zuständig ist. Bei der "vermischten" Lösung von dir und die Form-Klasse zuständig für das Anzeigen der Daten und das Laden der Daten. Und das ist ein und zuviel 😃

Hoffe es hilft dir weiter.

mfG Gü

Repository, Trennung UI Logik, SoC, Linq, MVC, Entity Framework, Ado.net EF, Speedski

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!"

B
Brain-Patter Themenstarter:in
12 Beiträge seit 2011
vor 12 Jahren

👍 👍 👍 👍 👍 👍 👍

Man man man jetzt komme ich mir aber ein bisschen dumm vor.

Tausend Dank für deine Antwort und vor allem für deinen Beispiel-Source!

Ich hab es jetzt endlich kapiert.

6.911 Beiträge seit 2009
vor 12 Jahren

Hallo Brain-Patter,

noch als Ergänzung da ich es vorhin nicht erwähnt habe: den gezeigten Code kannst du als MVC auffassen wenn die Controls der Form (hier: das DataGridView) die View sind, der Ereignishandler (hier btnLadeKunden_Click) der Controller und das Model aus dem Repository und MeinKundenEintrag besteht.

Freut mich dass du es damit kapiert hast, aber dumm vorkommen musst du dir deshalb auch nicht. Jeder hat mal begonnen...

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!"