2 Stimmen

Refaktorierung von Linq zu Sql

Gibt es eine Möglichkeit, Linq zu Sql zu refaktorisieren und die Vorteile der späten Auswertung zu nutzen? Gibt es eine Möglichkeit, Objekt-Initilizer-Code wiederzuverwenden?

Ich habe Geschäftsobjekte, die in einer Datenbank persistiert werden und über eine separate Linq to Sql-Schicht hydriert werden.

Ich möchte in der Lage sein, Code aus mehreren Abfragen wiederzuverwenden, die genau das Gleiche tun. Der Teil der Abfrage, den ich wiederverwenden möchte, ist der Teil der Objekterstellung. Ich möchte auch weiterhin die Vorteile der späten Auswertung nutzen (nur die gewünschten Spalten aus der Datenbank abrufen).

Die folgenden Beispiele sind sehr einfach und einige der Namen wurden zum Schutz der Unschuldigen geändert.

Muster 1

void GetUserById(Guid userId)
{
    IQueryable<LinqLayer.User> x =
        from user in dataContext.Users
        where user.UserID == userId
        select user;

    IQueryable<BusinessLayer.User> y = hydrateUser(x);

    // Acutally execute the query against the database.
    BusinessLayer.User user = y.First();
}

void GetUserByName(string name)
{
    IQueryable<LinqUser> x =
        from user in dataContext.Users
        where user.FirstName == name
        select user;

    IQueryable<User> y = hydrateUser(x);

    // Acutally execute the query against the database.
    User user = y.First();
}

IQueryable<User> hydrateUser(IQueryable<LinqUser> x)
{
    IQueryable<User> y;
        y = from item in x
        select new User
        {
            ID = item.UserID,
            FirstName = item.FirstName,
            MiddleName = item.MiddleName,
            LastName = item.LastName,
        };
    return y;
}

In Probe 1 sind mehrere Dinge im Gange. In diesem Beispiel kann ich die Vorteile der späten Auswertung von linq to sql nutzen. Wenn Sie sich die Datenbankabfragen ansehen, werden nur die Spalten ausgewählt, an denen ich interessiert bin (in hydrateUser als ID, Vorname usw. aufgeführt). Das ist gut, denn ich kann den Code in hydrateUser wiederverwenden.

Beispiel 2:

IQueryable<User> hydrateUser(IQueryable<LinqUser> x)
{
    IQueryable<User> y;
        y = from item in x
        select new User
        {
            ID = item.UserID,
            FirstName = item.FirstName,
            MiddleName = item.MiddleName,
            LastName = item.LastName,
            ... Big long list of properties
        };
    return y;
}

IQueryable<User> hydrateUserWithPermissions(IQueryable<LinqUser> x)
{
    IQueryable<User> y;
        y = from item in x
        select new User
        {
            ID = item.UserID,
            FirstName = item.FirstName,
            MiddleName = item.MiddleName,
            LastName = item.LastName,
            ... Big long list of properties
            PermissionList = item.Permissions
        };
    return y;
}

Beispiel 2 beginnt zu scheitern, wenn ich hydrateUser verwenden und auch ein zugehöriges Objekt hydratisieren möchte. Zum Beispiel, Hydratisierung einer Liste von Berechtigungen. Ich muss jetzt eine ganze separate Funktion abspinnen, die die zusätzliche Hydratisierung durchführt. Dies ist weniger als wünschenswert, wenn ich viele weitere Eigenschaften habe, die ich initialisiere.

Beispiel 3

IQueryable<User> hydratePermissions(IQueryable<LinqUser> x)
{
    IQueryable<User> y;
        y = from item in x
        select new User
        {
            PermissionList = item.Permissions
        };
    return y;
}

IQueryable<User> hydrateUser(IQueryable<LinqUser> x)
{
    IQueryable<User> y;
        y = from item in x
        select new User
        {
            ID = item.UserID,
            FirstName = item.FirstName,
            MiddleName = item.MiddleName,
            LastName = item.LastName,
            ... Big long list of properties
        };
    return y;
}

Ich möchte die Abfrage mit einem Code wie in Beispiel 3 erstellen können. Irgendwie versuchen, die Vorteile beider Funktionen zu nutzen. Und machen Sie nur einen Abstecher in die Datenbank. Dies funktioniert jedoch nicht.

Beispiel 4

User newUpUserFromLinqUser(LinqUser item)
{
    y = new User
        {
            ID = item.UserID,
            FirstName = item.FirstName,
            MiddleName = item.MiddleName,
            LastName = item.LastName,
        };
    return y;
}

Beispiel 4 ist nah an, was ich will, aber verliert die Ausdrucksauswertung, die linq to sql verwendet, um späte Auswertung zu tun. Alle Felder werden in der Abfrage zurückkommen. Noch schlimmer ist, wenn Code wie dieser eine untergeordnete Beziehung ist, wird ein Aufruf an die Datenbank für jedes Kind gemacht. Das ist in unserer Situation inakzeptabel.

Zusätzliche Hinweise

Die Bandbreite ist knapp bemessen. Wir kontrollieren genau, welche Daten über die Leitung kommen, daher ist es sehr wichtig, dass die Abfragen so schlank wie möglich sind.

Ich habe mir angesehen LinqKit und obwohl es so aussieht, als könnte es für meine Bedürfnisse funktionieren, würde ich "out of the box" bevorzugen.

Zum jetzigen Zeitpunkt steht die Gesamtarchitektur nicht zur Debatte.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X