2017-05-08 4 views
1

Ich habe zwei Viewmodels (Produkt und Teil):JSON Serialisierung dauert sehr lange Zeit

public class ProductViewModel 
{ 
    public int Id { get; set; } 

    public string Name { get; set; } 

    public string Description { get; set; }  

    public bool IsActive { get; set; } 

    public IEnumerable<PartViewModel> Parts { get; set; } 
} 

public class PartViewModel 
{ 
    public int Id { get; set; } 

    public string Name { get; set; } 

    public bool IsActive { get; set; } 
} 

ich ein EF Core-Abfrage ausführen, die 1727 Produkte mit mindestens 1 Teil pro Produkt zurückgibt. Ein Beispiel für eine Rückkehr von 1 davon würde als solche zu JSON serialisiert:

[ 
    { 
     "Id":8761, 
     "Name":"Product Name 1", 
     "Description":"This is a product", 
     "IsActive":true, 
     "Parts":[ 
     { 
      "Id":103767, 
      "Name":"Name 1" 
      "IsActive":true 
     }, 
     { 
      "Id":156436, 
      "Name":"Name 2", 
      "IsActive":true 
     }, 
     { 
      "Id":109436, 
      "Name":"Name 3", 
      "IsActive":true 
     } 
     ] 
    } 
] 

Nun, dies funktioniert gut mit einer Abfrage, wo ich .Nehmen (10), wenn auch scheinbar langsam, aber wenn ich versuche, und serialisiert 1727 Aufzeichnungen, es niedergebrannt und eine Wartezeit von fünf Minuten nicht einmal den Serialisierungsprozess abgeschlossen.

versuchte ich Json.Net als solche mit:

var ret = JsonConvert.SerializeObject(products, new JsonSerializerSettings { Formatting = Formatting.Indented }); 

entschied ich mich nur zu versuchen und verwenden JsonConvert von Json.Net, weil in meiner Controller-Aktion, beim Versuch, eine JsonResult zurückzukehren, den folgenden Code konvertieren mein Objekt JSON hatte die gleiche Effizienz Ausgabe:

return Json(products); 

ich die Produkte über EF-Core als solche erhalten:

var products = _context.Products.OrderBy(o => o.Name).Where(w => w.IsActive //all products are active 
      && (w.Parts.Count(c => c.IsActive) > 0)) //remove parts that are 
      .Select(pr => new ProductViewModel 
      { 
       Id = pr.Id, 
       Name = pr.Name, 
       Description = pr.Description, 
       IsActive = pr.IsActive, 
       Parts = pr.Parts.OrderBy(o => o.Name).Where(w => w.IsActive) //all parts are active 
       .Select(prt => new PartViewModel 
       { 
        Id = prt.Id, 
        Name = prt.Name, 
        IsActive = prt.IsActive, 
       }) 
      }).ToList(); 

Was kann ich tun?

+1

Lesen Sie [fragen], zeigen Sie, wie genau Sie 'Produkte' erhalten. – CodeCaster

+1

Sind Sie sicher, dass der Serialisierungsprozess so lange dauert? Wahrscheinlich möchten Sie auch eine Art Paging auf Ihrem Server implementieren, um zu vermeiden, dass der Arbeitsspeicher knapp wird. –

+0

Ich habe die Abfrage hinzugefügt, @CodeCaster – crackedcornjimmy

Antwort

1

Serialisierung ist nicht die große Sache, es ist leicht zu bemerken, jetzt, da Sie die LINQ-Abfrage hinzugefügt haben, dass das Problem das schlechte SQL Entity Framework daraus generiert.

Zuerst sollten Sie eifrig laden verwenden, um Ihre Produkttabelle mit der Teiletabelle zu verbinden. Sie können das einfach tun, indem Sie einen Methodenaufruf Include hinzufügen.

_context.Products.Include(p => p.Parts) 

Wenn dies nicht getan wird, führt die Abfrage tatsächlich N + 1 Abfragen. Sie sollten einen einfachen Trick verwenden, um die tatsächlichen SQL-Abfragen zu beobachten, die Ihre Abfrage ausführt, indem Sie diesen Code zu Ihrer DbContext hinzufügen. (Tun Sie dies nur, wenn Sie EF6 verwenden, EF-Core tut Abfrageprotokollierung für Sie.)

public YourDBContext() 
{ 
    #if DEBUG 
    this.Database.Log = msg => 
    { 
     Debugger.Log(1, "ALL", "EF DB SQL: " + msg + Environment.NewLine); 
    }; 
    #endif 
} 

Eine weitere Bedingung, die die Abfrage nehmen lang .Where(w => w.IsActive && (w.Parts.Count(c => c.IsActive) > 0)) tut. Ich denke, Entity Framework erzeugt eine HAVING-Klausel, aber es würde helfen, wenn Sie das generierte SQL zur Optimierung der Abfrage bereitstellen würden.

Schließlich eine Microoptimization in Ihrer Select-Methode wäre, um die Parts-Eigenschaft holen Ausdruck durch ändern.

// other properties ... 
Parts = pr.Parts.Where(w => w.IsActive).OrderBy(o => o.Name), 
// other properties ... 

Dies würde verhindern, dass Ihre Datenbank die inaktiven Teile abruft und sortiert.

Verwandte Themen