2016-06-02 3 views
1

Ich habe folgende Datenbankkontext, die ich mit Entitry Framework verwendenICollection in Domain-Modell Leistung

public class MainContext: DbContext 
{ 
    public MainContext() 
     : base("name=MainContext") 
    { } 

    public virtual DbSet<Device> Devices { get; set; } 
    public virtual DbSet<Point> Points { get; set; } 
} 

Mit folgenden Domain-Modell

public class Point 
{ 
    [Key] 
    public int Id { get; set; } 

    public string Info { get; set; } 
    public DateTime FixTime { get; set; } 

    public int DeviceId { get; set; } 
    public virtual Device Device { get; set; } 
} 

public class Device 
{ 
    [Key] 
    public int Id { get; set; } 

    public int SomeValue { get; set; } 

    public virtual ICollection<Point> Points { get; set; } 

    public bool IsActive() 
    { 
     Point lastPoint = Points.LastOrDefault(); 
     if (lastPoint == null) 
     { 
      return false; 
     } 
     else 
     { 
      var diff = DateTime.Now - lastPoint.FixTime; 

      if (diff.TotalSeconds > 10) 
      { 
       return false; 
      } 
      else 
      { 
       return true; 
      } 
     } 
    } 
} 

ich vor großen Leistungsproblem Aufruf IsActive() -Methode in die Geräteklasse. Soweit ich das sehen kann, fragt es wegen des Aufrufs von Points.LastOrDefault() alle verfügbaren Datenbankeinträge für das Gerät ab und nicht nur das einzige. Ich verstehe, dass es wegen der Verwendung von ICollection in meiner Klasse ist, aber das ist Entity Framework-Nachfrage. Gibt es eine Möglichkeit, den einzigen Datensatz in einer solchen Situation abzufragen, oder ist es nur ich, die Methode an einem falschen Ort zu platzieren?

Antwort

1

Gibt es eine Möglichkeit, den einzigen Datensatz in einer solchen Situation abzufragen, oder ist es nur ich die Methode an einem falschen Ort?

Wenn Sie mich fragen, letzteres. Sie wissen besser als Entity Framework, was genau abgefragt werden soll: Sobald Sie auf die lazy-loaded Navigationssammlungseigenschaft Points zugreifen, wird die gesamte Sammlung für dieses Gerät geladen.

Auch macht LastOrDefault() wenig Sinn in einer Datenbankumgebung, in der das Umkehren einer Sorte relativ billig ist.

Auch since you specify no order, the order isn't guaranteed, so this code is guaranteed to break some day (LastOrDefault() returning a different record).

Ich mag Entitätsmodelle nicht, die Abfragen ausführen, zumindest nicht im Fall eines ORM und insbesondere Entity Framework, also würde ich diese Logik in eine separate Klasse verschieben. Nennen Sie es ein PointGetter oder geben Sie ihm einen Namen.

Dort, können Sie die Abfrage tun können:

public class PointGetter 
{ 
    public Point GetLastPoint(DbContext dbContext, Device device) 
    { 
     var lastPointForDevice = dbContext.Points 
              .Where(p => p.Device == device) 
              .OrderByDescending(p => p.FixTime) 
              .FirstOrDefault(); 
     return lastPointForDevice; 
    } 
} 
+0

Nun, um mein Problem zu lösen, schließlich habe ich so etwas gemacht, aber ich fühle, dass es nicht der beste Weg ist, es sollte getan werden. – hitry

0

Warum versuchen Sie nicht ein .OrderBy oder OrderByDescending und dann . Sofern Sie die entsprechenden Indizes in Ihrer DB haben, sollte dies schnell genug sein und Sie nur einen Datensatz zurückbringen.

+0

, dass der erste war, was ich tat, verwendet OrderByDescending und FirstOrDefault. Ich habe auch versucht, Take (1) vor dem Aufruf von FirstOrDefault zu verwenden. Abfrage, dass EF generiert sowieso Anrufe für alle Datensätze/ – hitry

Verwandte Themen