Frage Linq zu SQL Stored Procedures mit mehreren Ergebnissen


Wir haben den folgenden Ansatz verfolgt, um die Daten aus mehreren Ergebnissen mit LINQ To SQL zu erhalten

CREATE PROCEDURE dbo.GetPostByID
(
    @PostID int
)
AS
    SELECT    *
    FROM      Posts AS p
    WHERE     p.PostID = @PostID

    SELECT    c.*
    FROM      Categories AS c
    JOIN      PostCategories AS pc
    ON        (pc.CategoryID = c.CategoryID)
    WHERE     pc.PostID = @PostID

Die aufrufende Methode in der Klasse, die von DataContext erbt, sollte folgendermaßen aussehen:

[Database(Name = "Blog")]
public class BlogContext : DataContext
{
    ... 

    [Function(Name = "dbo.GetPostByID")]
    [ResultType(typeof(Post))]
    [ResultType(typeof(Category))]
    public IMultipleResults GetPostByID(int postID)
    {
        IExecuteResult result = 
            this.ExecuteMethodCall(this, 
                  ((MethodInfo)(MethodInfo.GetCurrentMethod())), 
                  postID);

        return (IMultipleResults)(result.ReturnValue);
    }
}

Beachten Sie, dass die Methode nicht nur mit dem Function-Attribut versehen ist, das dem Namen der gespeicherten Prozedur entspricht, sondern auch mit den Attributen ReturnType und den Typen der Ergebnismengen, die von der gespeicherten Prozedur zurückgegeben werden. Darüber hinaus gibt die Methode eine untypisierte Schnittstelle von IMultipleResults zurück:

public interface IMultipleResults : IFunctionResult, IDisposable
{
    IEnumerable<TElement> GetResult<TElement>();
}

Das Programm kann diese Schnittstelle verwenden, um die Ergebnisse abzurufen:

BlogContext ctx = new BlogContext(...);

IMultipleResults results = ctx.GetPostByID(...);

IEnumerable<Post> posts = results.GetResult<Post>();

IEnumerable<Category> categories = results.GetResult<Category>();

In den obigen gespeicherten Prozeduren hatten wir zwei Select-Abfragen 1. Wählen Sie eine Abfrage ohne Verknüpfung 2. Wählen Sie Abfrage mit Join

Aber in der obigen zweiten Auswahlabfrage stammen die Daten, die angezeigt werden, aus einer der Tabellen, d. H. Aus der Kategorie-Tabelle. Aber wir haben Join verwendet und möchten die Datentabelle mit den Ergebnissen aus beiden Tabellen anzeigen, d. H. Aus Kategorien sowie PostCategories.

  1. Bitte lassen Sie mich wissen, wie Sie dies mit LINQ to SQL erreichen können
  2. Was ist der Performance-Trade-off, wenn wir den obigen Ansatz verwenden, um den obigen Ansatz mit einfachem SQL zu implementieren?

15
2017-12-16 14:22


Ursprung


Antworten:


Scott Guthrie (der Typ, der die .Net-Entwicklerteams bei MS leitet) behandelte, wie das auf seinem Blog vor ein paar Monaten viel besser funktioniert, als ich es jemals könnte, Link hier. Auf dieser Seite befindet sich ein Abschnitt mit dem Titel "Behandlung mehrerer Ergebnisformen von SPROCs". Das erklärt, wie mehrere Ergebnisse von gespeicherten Procs unterschiedlicher Formen (oder derselben Form) verarbeitet werden.

Ich empfehle sehr, seinen RSS-Feed zu abonnieren. Er ist ziemlich viel DAS maßgebliche Quelle für alle Dinge .Net.


9
2017-12-16 14:59



Heya Kumpel - geht das?

IEnumerable<Post> posts;
IEnumerable<Category> categories;

using (BlogContext ctx = new BlogContext(...))
{
    ctx.DeferredLoadingEnabled = false; // THIS IS IMPORTANT.
    IMultipleResults results = ctx.GetPostByID(...);
    posts = results.GetResult<Post>().ToList();
    categories = results.GetResult<Category>().ToList();
}
// Now we need to associate each category to the post.
// ASSUMPTION: Each post has only one category (1-1 mapping).
if (posts != null)
{
    foreach(var post in posts)
    {
        int postId = post.PostId;
        post.Category = categories
            .Where(p => p.PostId == postId)
            .SingleOrDefault();
    }
}

OK. Lass uns das durchbrechen.

Zunächst einmal, eine nette Verbindung innerhalb eines using Blocks (so ist es schön entsorgt).

Als nächstes sorgen wir dafür VERZÖGERTE LADUNG ist aus. Andernfalls, wenn Sie versuchen und das Set (z. post.Category == blah) es wird sehen, dass es null ist, lazy-load die Daten (z. B. eine Tour durch die Datenbank) setze die Daten und DANN überschreibe das, was gerade von der db gezogen wurde, mit dem Ergebnis von dort Where(..) Methode. Puh! Zusammenfassung: Stellen Sie sicher, dass das verzögerte Laden für den Gültigkeitsbereich der Abfrage deaktiviert ist.

Zuletzt, für jeden Beitrag, iterieren und setzen Sie die Kategorie aus der zweiten Liste.

Hilft das?

BEARBEITEN

Es wurde so gefixt, dass es keinen Aufzählungsfehler durch Aufruf des ToList() Methoden.


7
2018-01-20 05:42



Nur neugierig, wenn ein Post eine oder mehrere Kategorien hat, ist es möglich, anstelle der for-Schleife, die Post.PostCategories mit der Liste der Kategorien (eins zu viele), alles in einem Schuss, mit einem JOIN zu laden?

var rslt = from p in results.GetResult<Post>()
           join c in results.GetResult<Category>() on p.PostId = c.PostID
           ...
           p.Categories.Add(c)

0
2017-12-20 13:51