Comme le titre le suggère, la première requête pose un problème avec une base de données SQL Server utilisant Entity Framework. J'ai essayé de chercher une réponse, mais personne ne semble avoir de solution à ce problème.
Les tests ont été réalisés dans Visual Studio 2012 à l'aide d'Entity Framework 6. J'ai également utilisé le modèle de vues T4 pour précompiler les vues. La base de données était sur un SQL Server 2008. Nous avons environ 400 POCO (400 fichiers de mappage), nous n'avons que 100 lignes de données dans la table de base de données.
La capture suivante est mon code de test et mon résultat.
static void Main(string[] args){
Stopwatch st=new Stopwatch();
st.Start();
new TestDbContext().Set<Table1>.FirstOrDefault();
st.stop();
Console.WriteLine("First Time "+st.ElapsedMilliseconds+ " milliseconds");
st.Reset();
st.Start();
new TestDbContext().Set<Table1>.FirstOrDefault();
st.stop();
Console.WriteLine("Second Time "+st.ElapsedMilliseconds+ " milliseconds");
}
Résultats de test
First Time 15480 milliseconds
Second Time 10 milliseconds
Sur la première requête, EF compile le modèle. Cela peut prendre un certain temps pour un modèle de cette taille.
Voici 3 suggestions: http://www.fusonic.net/fr/blog/2014/07/09/three-steps-for-fast-entityframework-6.1-first-query-performance/
Un résumé:
Je voudrais également m'assurer que je compile l'application en mode publication lorsque je fais les tests.
Une autre solution consiste à scinder le DBContext. 400 entités, c'est beaucoup et il devrait être plus agréable de travailler avec de plus petits morceaux. Je ne l'ai pas essayée mais je suppose qu'il serait possible de construire les modèles un par un, ce qui signifie qu'aucune charge ne prend 15 secondes. Voir le message de Julie Lerman https://msdn.Microsoft.com/en-us/magazine/jj883952.aspx
Avec EF Core, vous pouvez tricher et charger le modèle tôt après avoir appelé services.AddDbContext
(vous pouvez probablement faire quelque chose de similaire avec EF6 aussi, mais je ne l’ai pas testé).
services.AddDbContext<MyDbContext>(options => ...);
var options = services.BuildServiceProvider()
.GetRequiredService<DbContextOptions<MyDbContext>>();
Task.Run(() =>
{
using(var dbContext = new MyDbContext(options))
{
var model = dbContext.Model; //force the model creation
}
});
Cela créera le modèle de dbcontext dans un autre thread pendant que le reste de l'initialisation de l'application est terminé (et peut-être d'autres échauffements) et le début d'une demande. De cette façon, il sera prêt plus tôt. Lorsque vous en aurez besoin, EFCore attendra que le modèle soit créé s'il n'est pas encore terminé. La Model
est partagée entre toutes les instances de DbContext. Vous pouvez donc déclencher et oublier ce dbcontext factice.
Vous pouvez essayer quelque chose comme ça: (ça a marché pour moi)
protected void Application_Start()
{
Start(() =>
{
using (EF.DMEntities context = new EF.DMEntities())
{
context.DMUsers.FirstOrDefault();
}
});
}
private void Start(Action a)
{
a.BeginInvoke(null, null);
}
Si vous avez beaucoup de tables qui ne sont pas utilisées sur c #, excluez-les.
Ajouter une classe partielle, ajouter le code suivant et référencer cette fonction sur OnModelCreating
void ExcludedTables(DbModelBuilder modelBuilder)
{
modelBuilder.Ignore<Table1>();
modelBuilder.Ignore<Table>();
// And so on
}
ça marche pour moi:
using (MyEntities db = new MyEntities())
{
db.Configuration.AutoDetectChangesEnabled = false; // <----- trick
db.Configuration.LazyLoadingEnabled = false; // <----- trick
DateTime Created = DateTime.Now;
var obj = from tbl in db.MyTable
where DateTime.Compare(tbl.Created, Created) == 0
select tbl;
dataGrid1.ItemsSource = obj.ToList();
dataGrid.Items.Refresh();
}