2017-08-24 7 views
1

Ich bin neu in Entity Framework und linq. Ich arbeite mit asp.net mvc 5 und C#. ich eine Abfrage mit dynamischer Sortierung wie folgt schreiben:Entity Framework linq orderby Funktion

public static IEnumerable<T> OrderByDynamic<T>(this IEnumerable<T> source, string propertyName, bool Ascending) 
{ 
    if (Ascending) 
     return source.OrderBy(x => x.GetType().GetProperty(propertyName).GetValue(x, null)); 
    else 
     return source.OrderByDescending(x => x.GetType().GetProperty(propertyName).GetValue(x, null)); 
    } 

und in meinem Repository kann ich schreiben:

string sortExpr = "name"; 
_objDB.hotels.Where(s => (s.city_id = 1)) 
      .OrderByDynamic(sortExpr, Ascending).ToList(); 

Dieser Code funktioniert gut, wenn sie auf einer Spalte einer Tabelle ist das Sortieren, aber ich brauche nach einer SQL-Funktion sortieren. Ich trat in die Funktion in das .edmx Modell mit dem folgenden Code

[EdmFunction("hotelReservation.Core.Data", "getHotelMinPrice_cap")] 
public static int getHotelMinPrice_cap(int Hotel_id, int capacity, DateTime enter_date, DateTime exit_date) 
{ 
    throw new NotSupportedException("Direct calls are not supported."); 
} 

und meiner SQL-Auswahl ist so etwas wie:

select * 
from hotel 
where city_id = 1 
order by dbo.getHotelMinPrice_cap(hotel.id,1,'2001-01-01', '2021-01-01') 

Wie kann ich die letzte SQL-Abfrage mit dynamischer Sortierung in Linq schreiben?

+0

Sortieren nach Verwendung einer Funktion eine schlechte Praxis ist. Sie sollten Ihre Abfrage zuerst optimieren. Stellen Sie Ihre Funktion 'getHotelMinPrice_cap' zur Verfügung, damit der Weg optimiert werden kann. –

+0

select min (room_price.price) von room_price, room_definition wo room_price.roomDef_id room_definition.ID = und room_definition.Hotel_id = Hotel_ID und room_definition.capacity = und Kapazität (room_price.start_date zwischen enter_date und exit_date oder room_price.stop_date zwischen enter_date und exit_date) – saeedeh

+0

Ich frage nach SQL-Funktion. –

Antwort

0

Dank Harald Coppoolse für die Antwort ich es endlich wie dies tat:

_objDB.hotels .Select(h=> new { id= h.id, name=h.name, star=h.star, 
        minPrice1 = hotel.getHotelMinPrice_cap(h.id, 1, model.date_check_in, model.date_check_out)}) 
.Where(s => (s.city_id = 1)) 
.OrderByDynamic(sortExpr, Ascending).ToList(); 

In diesem Fall kann ich sortExpr = minPrice1; wählen und es wird durch die SQL-Funktion Art sein.

auch änderte ich die OrderByDynamic Funktion als Gebrüll:

public static IQueryable<T> OrderByDynamic<T>(this IQueryable<T> q, string SortField, bool Ascending) 
     { 
      var param = Expression.Parameter(typeof(T), "p"); 
      var prop = Expression.Property(param, SortField); 
      var exp = Expression.Lambda(prop, param); 
      string method = Ascending ? "OrderBy" : "OrderByDescending"; 
      Type[] types = new Type[] { q.ElementType, exp.Body.Type }; 
      var mce = Expression.Call(typeof(Queryable), method, types, q.Expression, exp); 
      return q.Provider.CreateQuery<T>(mce); 
     } 

, die ich auf Seite gefunden: https://stackoverflow.com/a/7265354/8509940

1

Ihre Lösung stellt mehrere Probleme:

  • Sie OrderBy eine Eigenschaft mit Namen der Hoffnung, dass die Objekte, die Sie haben diese Eigenschaft bestellen. Was ist, wenn Ihre Objekte diese Eigenschaft nicht haben?
  • SQL versteht nicht funktioniert wie GetProperty(), so dass diese Anordnung in einem lokalen Speicher (AsEnumerable) anstelle des viel schneller SQL Server (AsQueryable) durchgeführt werden muss.
  • Sie verwenden eine gespeicherte Prozedur, um zu bestellen.

    public static IEnumerable<T, TKey> OrderByDynamic<T>(this IEnumerable<T> source, 
        Func<T, TKey> keySelector, System.ComponentModel.ListSortDirection sortDirection) 
    { 
        if (sortDirection == ListSortDirection.Ascending) 
         return source.OrderBy(keySelector); 
        else 
         return source.OrderByDescending(keySelector); 
    } 
    

    Verbrauch wäre wie:

Die ersten beiden Probleme können durch Änderung der Parameter propertyName durch eine Func<TSource, TKey> keySelector leicht lösende

var result = Students.OrderByDynamis(student => student.Name, ListSortDirection.Ascending); 

Der Vorteil dieser Methode, dass Ihr Compiler wird sich beschweren, wenn Sie versuchen, durch eine nicht vorhandene Eigenschaft zu bestellen. Außerdem kann OrderByAsQueryable durchgeführt werden; Es kann von Ihrer Datenbank statt im lokalen Speicher ausgeführt werden.

Es ist wirklich eine schlechte Idee, eine Zeichenfolge zu verwenden, um die gewünschte Eigenschaft auszuwählen.

Wenn Sie einen Tippfehler machen, werden Sie dies nur zur Laufzeit feststellen. Außerdem: Wenn Sie wissen, was Sie während der Entwicklung Ihres Codes als Zeichenkette für Ihre propertyName eingeben müssen, wissen Sie auch, welche Art von Objekten Sie sortieren werden. Sie könnten also stattdessen eine keySelector schreiben.

Ihr zweites Problem ruft die gespeicherte Prozedur als Sortierreihenfolge auf. Dies ist relativ einfach zu lösen, wenn Sie zuerst die gespeicherte Prozedur aufrufen und dann Bestellung durch den Rückgabewert:

var result = Hotels.Where(hotel => hotel...) 
    .Select(hotel => new 
    { 
     StoredProcedureValue = CallStoredprocedure(hotel,...), 
     Hotel = hotel, 
    }) 
    .AsEnumerable() // bring the result to local memory 
    .Orderby(item => item.StoredProcedureValue) 
    .Select(item => item.Hotel); 

nur die Hotels, die in den lokalen Speicher übertragen in Ihrem End-Ergebnis sein wird, zusammen mit dem Ergebnis der die StoredProcedures. Sie wurden nur für die Hotels aufgerufen, die Sie in Ihrem Endergebnis verwenden werden.

Die Sortierung erfolgt jedoch im lokalen Speicher.Wenn Sie auch möchten, dass diese Sortierung auf Datenbankseite erfolgt, müssen Sie eine neue gespeicherte Prozedur erstellen, die die andere gespeicherte Prozedur aufruft, bevor die Sortierung durchgeführt wird.

+0

Vielen Dank für Ihre Antwort. Ich weiß nicht, was "StoredProcedureValue" und "CallStoredprocedure" sind, die Sie geschrieben haben! was sind sie ?? Ich möchte eine Funktion mit dem Namen 'getHotelMinPrice_cap' verwenden – saeedeh

+0

Es scheint, dass Sie mit anonymen Typen nicht vertraut sind. In der 'Where' -Statement nehme ich die Sammlung von' Hotels' und von jedem Gegenstand in dieser Sammlung, die ich bequemerweise mit dem Bezeichner 'hotel' identifiziere, erstelle ich ein neues Objekt der anonymen Klasse, mit zwei Eigenschaften:' StoredProcedureValue' und ' Hotel'. Ich weiß nicht, wie Sie den Wert der gespeicherten Prozedur erhalten, also habe ich gerade eine Funktion aufgerufen, die das so macht, wie Sie es normalerweise tun. Der Orderby nimmt als Eingabe diesen anonymen Typ http://geekswithblogs.net/BlackRabbitCoder/archive/2012/06/21/c.net-little-wonders-the-joy-of-anonymous-types.aspx –