Comment optimiser la requête suivante? Nous examinons les requêtes de structure d'entité dans la base de données et essayons d'apprendre.
using (var context = new DataDbContext())
{
var query = (from u in content.Parents
where u.Children.Any(y = y.Age > 13)
select u);
foreach (var parent in query.ToList())
{
foreach (var children in owner.Children)
{
children.IsTeenager= true;
}
}
context.SaveChanges();
}
5 Réponses :
Il n'y a pas grand chose à optimiser, vous pouvez réduire le code. La logique est un peu étrange
using (var context = new DataDbContext())
{
var parents = content.Parents.Where(o => o.Children.Any(x => x.Age > 13));
foreach (var child in parents.SelectMany(o => o.Children))
{
children.IsTeenager= true;
}
context.SaveChanges();
}
ou
using (var context = new DataDbContext())
{
foreach (var child in content.Parents.Where(o => o.Children.Any(x => x.Age > 13)).SelectMany(o => o.Children))
{
children.IsTeenager= true;
}
context.SaveChanges();
}
Il n'y a pas de moyen formidable de simplifier ce que vous faites ici. EF a tendance à vous pousser à lire un tas de données à partir du magasin de données, à mettre à jour les entités localement, puis à réécrire ces modifications. C'est évidemment assez lent. Cependant, ce que vous essayez de faire ici est d'obtenir tous les enfants et de définir la propriété IsTeenager afin que vous ne vous souciez même pas de l'objet Parent , vous pouvez simplement le faire :
context.Database.ExecuteSqlCommand("UPDATE Children SET IsTeenager = 1 WHERE Age < 13");
Bien sûr, il existe un moyen beaucoup plus simple de le faire en utilisant du SQL brut. Par exemple:
var children = context.Children.Where(c => c.Age < 13);
foreach(var child in children)
{
child.IsTeenager = true;
}
context.SaveChanges();
J'ai vu ce qui suit dans vos commentaires plus tôt (a depuis été supprimé):
c'était une question d'entretien d'embauche que j'avais eue il y a quelques mois, je ne suis même pas sûr
Si je devais poser cette question à quelqu'un lors d'un entretien d'embauche, j'espère qu'il m'informera de ce qui suit:
Age ! public class PersonModel
{
public DateTime BirthDate { get; set; }
public int Age { get; set; } // should be computed and mapped from sql
public bool IsTeenager { get; set; } // should be computed and mapped from sql
}
public class PersonModel
{
public DateTime BirthDate { get; set; }
public int Age
{
get
{
var today = DateTime.Today;
// Calculate the age.
var age = today.Year - BirthDate.Year;
// Go back to the year the person was born in case of a leap year
if (BirthDate > today.AddYears(-age)) age--;
return age;
}
}
public bool IsTeenager
{
get
{
return Age >= 13 && Age < 20;
}
}
}
La logique pour IsTeenager telle qu'elle est écrite n'est pas que «l'enfant» a plus de 13 ans, cela dépend aussi de l'âge de ses frères et sœurs.
@CharlesMager Ouais, c'est certainement faux aussi.
@DavidG Je suppose qu'en tant que question d'entretien d'embauche, ils recherchent simplement que vous repériez le problème sélectionné N + 1. Mais qui sait?!
@CharlesMager - Si je posais cette question, je serais plus heureux si quelqu'un pouvait signaler toutes les erreurs de logique et de conception au lieu de simplement regarder le N + 1. Mais c'est juste moi.
@CharlesMager Ouais, je commence à penser que c'était une mauvaise idée de répondre moi-même à cette question.
content.Children.Where(o => !o.IsTeenager && o.Age >= 13 && o.Age <= 19)
Lorsque vous souhaitez mettre à jour des données à l'aide d'Entity Framework, vous devez d'abord les récupérer dans la mémoire (soit par chargement hâtif, soit par chargement différé), puis les modifier.
Parfois, cela pose un problème N + 1. Cela signifie N + 1 appels au serveur de base de données. Et si vous utilisez un hébergement basé sur le cloud comme Azure ou AWS, vous êtes facturé par demande. Ce serait donc aussi coûteux financièrement.
Dans votre cas, je préférerais faire cela dans Yes Entity Framework, mais en utilisant la procédure stockée. Les requêtes simples sont utilisées mais je ne vous recommanderai pas de le faire de cette manière.
L'utilisation de la procédure stockée vous évitera d'apporter des données dans la mémoire et obtiendra le résultat en utilisant 1 appel de base de données.
Qu'est-ce qui vous fait penser qu'il doit être optimisé?
Vous voudrez peut-être vérifier l'âge dans la boucle interne; cela pourrait ne pas mettre à jour ce que vous voulez.
Cela semble assez simple. Vous ne pouvez pas mettre à jour les enregistrements sans interroger d'abord. La seule alternative serait de sauter l'entité et d'exécuter directement une instruction de mise à jour SQL.
La logique est un peu étrange. Définir les animaux de compagnie de tous les propriétaires sur
IsTeenager = truesi l'un animal qu'ils possèdent a plus de 13 ans?Cela ressemble à un problème courant de N + 1 Entity Framework. Il est également étrange que vous définissiez la propriété
IsTeenager, qui devrait être calculée en fonction de la propriétéAge.