2 Tabellen über Linq (EF) abfragen



  • Hallo,
    ich weiß nicht, ob ich mit meiner Frage überhaupt im richtigen Forum bin, aber da ich C# programmieren, hab ich mich einfach mal dafür entschieden.

    In meinem DataModel habe ich zwei Tabellen eingebunden.

    Nun würde ich gerne eine Abfrage über beide Tabellen machen, aber ich weiß nicht, wie ich die Daten zurück bekommen oder anderst ausgedrückt, was der "korrekte" Weg dabei ist.

    public static List<Collection> GetCollectionInfo(int iId)
            {
                try
                {
                    using (dbEntities ctx = new dbEntities())
                    {
                        var query = from i in ctx.tbl_collection
                                    join s in ctx.tbl_collectionstatus on i.collectionstatus
                                    equals s.collectionstatus
                                    where i.id == iId
    
    // Möglichkeit die ich kenne, aber nicht weiß, ob dies "richtig" ist.
    // eine eigene Klasse (Collection) schreiben und darüber die Daten abfragen:
    
                                    select new Collection
                                    {
                                        CollectionId = i.id,
                                        CollectionFr = i.cFrance
                                    };
                                    return query.ToList();
    }
    

    Meine Frage:
    So wie ich es hier mache geht es zwar, aber ist es denn tatsächlich notwendig, eine eigene Klasse dafür zu machen?
    Und falls nicht, wie würde der Weg ohne eine eigene Klasse aussehen?



  • Doch, es ist notwendig. Ich ich glaube schon deswegen, weil es mit anonymen(var) nicht möglich ist. Und selbst wenn würde ich, wenn ich deinen Code lesen würde, die Art wie er geschrieben ist verfluchen weil ich einfach nicht auf den ersten Blick sehe was los ist.

    Und so ganz nebenbei... Wir haben damals auch alles auf's EF gesetzt und wurden schwer enttäuscht was die Performance angeht. So einen Fall wie du haben wir auch sehr oft und was ich dir hier definitiv empfehlen kann ist, dein Statement hart zu schreiben oder in eine View auf dem Server zu erstellen und dann rufst du ExecuteStoreQuery<T> auf. Das mappen macht das EF dann für dich. Hat den Vorteil, dass du wirklich nur die Felder bekommst die du auch brauchst.



  • secondsun schrieb:

    Doch, es ist notwendig. Ich ich glaube schon deswegen, weil es mit anonymen(var) nicht möglich ist. Und selbst wenn würde ich, wenn ich deinen Code lesen würde, die Art wie er geschrieben ist verfluchen weil ich einfach nicht auf den ersten Blick sehe was los ist.

    Liegt das meinem Code, also an der Art wie ich programmiere, oder meinst du das allgemein mit Linq? 😕

    secondsun schrieb:

    So einen Fall wie du haben wir auch sehr oft und was ich dir hier definitiv empfehlen kann ist, dein Statement hart zu schreiben ...

    Was verstehst unter hart schreiben?



  • Moin,

    ne sorry so war das nicht gemeint. Ich habe mich ein bisschen falsch ausgedrückt. Der Code ist ok. Das war nur darauf bezogen, dass wenn es mit vars möglich wäre(ohne eine Klasse zu definieren), man nicht auf den ersten Blick sehen kann was los ist. Aber das ist Geschmackssache.

    Um deinen Code aber noch übersichtlicher zu machen könntest du folgendes tun:

    public static List<Collection> GetCollectionInfo(int iId)
            {
                try
                {
                    using (dbEntities ctx = new dbEntities())
                    {
                        return(from i in ctx.tbl_collection
                                    join s in ctx.tbl_collectionstatus on i.collectionstatus
                                    equals s.collectionstatus
                                    where i.id == iId
    
    // Möglichkeit die ich kenne, aber nicht weiß, ob dies "richtig" ist.
    // eine eigene Klasse (Collection) schreiben und darüber die Daten abfragen:
    
                                    select new Collection
                                    {
                                        CollectionId = i.id,
                                        CollectionFr = i.cFrance
                                    }).ToList();
    }
    

    Mit hart schreiben meine ich folgendes... Dein LINQ Statement wird ja mal irgendwann zu einem SQL Statement umgewandelt(Wie das aussieht kannst du übrigens beim Debuggen im Ausgabefenster sehen). Diese Umwandlung kostet aber Zeit. Zudem werden einfach mal beide Tabellen ausgelesen mit allen Feldern obwohl du nur zwei brauchst. Du solltest dir also aus Performancegründen auf dem SQL Server am besten eine Procedure anlegen der du deinen id übergibst und dann nur die Felder zurückliefer lässt die du wirklich brauchst. Belastet das Netzwerk nicht so wenn viele Clients arbeiten.

    Verstanden?



  • Danke für den Tipp, um den Code noch etwas übersichtlicher zu gestalten!

    secondsun schrieb:

    Diese Umwandlung kostet aber Zeit. Zudem werden einfach mal beide Tabellen ausgelesen mit allen Feldern obwohl du nur zwei brauchst.

    Das habe ich leider selbst schon bemerkt, besonders wenn die eine Tabelle dann auch sehr viele Datensätze enthält (~20.000). 😞

    secondsun schrieb:

    Du solltest dir also aus Performancegründen auf dem SQL Server am besten eine Procedure anlegen der du deinen id übergibst und dann nur die Felder zurückliefer lässt die du wirklich brauchst. Belastet das Netzwerk nicht so wenn viele Clients arbeiten.
    Verstanden?

    Verstanden ja, nur die Umsetzung ist mir noch nicht so ganz klar.
    Wie kann ich denn auf eine Stored Procedure über die Id zugreifen? Muss ich dazu wieder einen SQL Connector mit einbinden? Genau das wollte ich eigentlich vermeiden.



  • Hier mal ein Beispiel zu einer Prozedur mit Übergabeparameter(Firebird)

    CREATE PROCEDURE "DeineProzedur"(iId bigint not null) 
    returns (CollectionId bigint, CollectionFr bigint)
    as
    begin
      FOR SELECT co.id,
                 cost.cFrance,
          FROM tbl_collection       co
          JOIN tbl_collectionstatus cost ON cost.collectionstatus = co.collectionstatus
          WHERE co.id = :iId
          INTO :CollectionId,
               :CollectionFr,
      DO BEGIN
         suspend;
      END
    END
    

    Dein C# COde

    public static List<Collection> GetCollectionInfo(int iId)
    {
        try
        {
            using (dbEntities ctx = new dbEntities())
            {
                return(ctx.ExecuteStoreQuery<Collection>("SELECT * FROM DeineProzedur(%1)").ToList();
            }
        }......
    }
    

    Verstanden?


Log in to reply