Aracılığıyla paylaş


ASP.NET 4 Web Uygulamasında Entity Framework 4.0 ile Performansı En Üst Düzeye Çıkarma

tarafından Tom Dykstra

Bu öğretici serisi , Entity Framework 4.0 ile Çalışmaya Başlama öğretici serisi tarafından oluşturulan Contoso Üniversitesi web uygulamasını oluşturur. Önceki öğreticileri tamamlamadıysanız, bu öğreticinin başlangıç noktası olarak oluşturduğunuz uygulamayı indirebilirsiniz . Öğretici serisinin tamamı tarafından oluşturulan uygulamayı da indirebilirsiniz. Öğreticiler hakkında sorularınız varsa bunları ASP.NET Entity Framework forumu'na gönderebilirsiniz.

Önceki öğreticide eşzamanlılık çakışmalarını işlemeyi gördünüz. Bu öğreticide Entity Framework kullanan bir ASP.NET web uygulamasının performansını geliştirmeye yönelik seçenekler gösterilir. Performansı en üst düzeye çıkarmak veya performans sorunlarını tanılamak için çeşitli yöntemler öğreneceksiniz.

Aşağıdaki bölümlerde sunulan bilgiler büyük olasılıkla çok çeşitli senaryolarda yararlı olacaktır:

  • İlgili verileri verimli bir şekilde yükleyin.
  • Görünüm durumunu yönetin.

Performans sorunları sunan tek tek sorgularınız varsa, aşağıdaki bölümlerde sunulan bilgiler yararlı olabilir:

  • NoTracking Birleştirme seçeneğini kullanın.
  • LINQ sorgularını önceden derleyin.
  • Veritabanına gönderilen sorgu komutlarını inceleyin.

Aşağıdaki bölümde sunulan bilgiler, son derece büyük veri modellerine sahip uygulamalar için yararlı olabilir:

  • Görünümleri önceden oluşturun.

Not

Web uygulaması performansı, istek ve yanıt verilerinin boyutu, veritabanı sorgularının hızı, sunucunun kuyruğa alabildiği istek sayısı ve bunlara ne kadar hızlı hizmet verebildiği ve hatta kullanmakta olabileceğiniz istemci betik kitaplıklarının verimliliği gibi birçok faktörden etkilenir. Uygulamanızda performans kritikse veya test veya deneyim uygulama performansının tatmin edici olmadığını gösteriyorsa, performans ayarlaması için normal protokolü izlemeniz gerekir. Performans sorunlarının nerede oluştuğunu belirlemek için ölçün ve ardından genel uygulama performansı üzerinde en büyük etkiye sahip olacak alanları ele alın.

Bu konu, temel olarak ASP.NET'de Özellikle Entity Framework'ün performansını geliştirmenin yollarına odaklanır. Veri erişiminin uygulamanızdaki performans sorunlarının biri olduğunu belirlerseniz buradaki öneriler yararlı olur. Belirtildiği gibi, burada açıklanan yöntemlerin genel olarak "en iyi yöntemler" olarak değerlendirilmemesi gerekir; çoğu yalnızca istisnai durumlarda veya çok özel performans sorunlarını gidermek için uygundur.

Öğreticiyi başlatmak için Visual Studio'yu başlatın ve önceki öğreticide üzerinde çalıştığınız Contoso University web uygulamasını açın.

Entity Framework'ün ilgili verileri bir varlığın gezinti özelliklerine yüklemesinin çeşitli yolları vardır:

  • Tembel yükleme. Varlık ilk kez okunduğunda ilgili veriler alınmaz. Ancak, bir gezinti özelliğine ilk kez erişmeye çalıştığınızda, bu gezinti özelliği için gereken veriler otomatik olarak alınır. Bu, veritabanına birden çok sorgu gönderilmesiyle sonuçlanır. Bu sorgulardan biri varlığın kendisi için, diğeri de varlıkla ilgili verilerin her alınması gerektiğinde alınır.

    Resim05

Hevesle yükleniyor. Varlık okunduğunda, onunla birlikte ilgili veriler de alınır. Bu genellikle gereken tüm verileri alan tek bir birleştirme sorgusuyla sonuçlanmıştır. Bu öğreticilerde daha önce gördüğünüz gibi yöntemini kullanarak Include istekli yüklemeyi belirtirsiniz.

Resim07

  • Açık yükleme. Bu, koddaki ilgili verileri açıkça almanız dışında gecikmeli yüklemeye benzer; bir gezinti özelliğine eriştiğinde otomatik olarak gerçekleşmez. Koleksiyonlar için gezinti özelliğinin Load yöntemini kullanarak ilgili verileri el ile yüklersiniz veya tek bir nesneyi barındıran özellikler için başvuru özelliğinin yöntemini kullanırsınız Load . (Örneğin, bir Department varlığın PersonReference.Load gezinti özelliğini yüklemek Person için yöntemini çağırırsınız.)

    Resim06

Özellik değerlerini hemen almadıkları için gecikmeli yükleme ve açık yükleme de ertelenmiş yükleme olarak bilinir.

Yavaş yükleme, tasarımcı tarafından oluşturulan bir nesne bağlamı için varsayılan davranıştır. SchoolModel.Tasarım Aracı dosyasını açarsanız. nesne bağlam sınıfını tanımlayan cs dosyası, üç oluşturucu yöntemi bulursunuz ve bunların her biri aşağıdaki deyimi içerir:

this.ContextOptions.LazyLoadingEnabled = true;

Genel olarak, alınan her varlık için ilgili verilere ihtiyacınız olduğunu biliyorsanız, veritabanına gönderilen tek bir sorgu genellikle alınan her varlık için ayrı sorgulardan daha verimli olduğundan, istekli yükleme en iyi performansı sunar. Öte yandan, bir varlığın gezinti özelliklerine yalnızca seyrek olarak veya yalnızca küçük bir varlık kümesi için erişmeniz gerekiyorsa, gecikmeli yükleme veya açık yükleme daha verimli olabilir, çünkü istekli yükleme size gerekenden daha fazla veri alabilir.

Bir web uygulamasında, ilgili veri gereksinimini etkileyen kullanıcı eylemleri, sayfayı işleyen nesne bağlamıyla bağlantısı olmayan tarayıcıda gerçekleştiğinden, gecikmeli yükleme oldukça az değere sahip olabilir. Öte yandan, bir denetimin veri bağlamasını yaptığınızda genellikle hangi verilere ihtiyacınız olduğunu anlarsınız ve bu nedenle her senaryoda uygun olan şeylere bağlı olarak istekli yükleme veya ertelenmiş yüklemeyi seçmek genellikle en iyisidir.

Ayrıca, veri bağlantısı denetimi nesne bağlamı atıldıktan sonra bir varlık nesnesi kullanabilir. Bu durumda, bir gezinti özelliğini yavaş yükleme girişimi başarısız olur. Aldığınız hata iletisi açık: "The ObjectContext instance has been disposed and can no longer be used for operations that require a connection."

Denetim, EntityDataSource gecikmeli yüklemeyi varsayılan olarak devre dışı bırakır. ObjectDataSource Geçerli öğretici için kullandığınız denetim için (veya nesne bağlamı sayfa kodundan erişiyorsanız), gecikmeli yüklemeyi varsayılan olarak devre dışı bırakabileceğiniz çeşitli yollar vardır. Nesne bağlamı örneği oluştururken bunu devre dışı bırakabilirsiniz. Örneğin, sınıfının oluşturucu yöntemine SchoolRepository aşağıdaki satırı ekleyebilirsiniz:

context.ContextOptions.LazyLoadingEnabled = false;

Contoso University uygulaması için nesne bağlamını otomatik olarak yavaş yüklemeyi devre dışı bırakacaksınız, böylece bağlam her başlatıldığında bu özelliğin ayarlanması gerekmez.

SchoolModel.edmx veri modelini açın, tasarım yüzeyine tıklayın ve özellikler bölmesinde Gecikmeli Yükleme Etkin özelliğini olarak Falseayarlayın. Veri modelini kaydedin ve kapatın.

Resim04

Görünüm Durumunu Yönetme

Güncelleştirme işlevselliği sağlamak için bir ASP.NET web sayfası, bir sayfa işlenirken varlığın özgün özellik değerlerini depolamalıdır. Geri gönderme işlemi sırasında denetim, varlığın özgün durumunu yeniden oluşturabilir ve değişiklikleri uygulamadan ve yöntemini çağırmadan önce varlığın AttachSaveChanges yöntemini çağırabilir. Varsayılan olarak, ASP.NET Web Forms veri denetimleri özgün değerleri depolamak için görünüm durumunu kullanır. Ancak görünüm durumu, tarayıcıya gönderilen ve tarayıcıdan gönderilen sayfanın boyutunu önemli ölçüde artırabilen gizli alanlarda depolandığından performansı etkileyebilir.

Görünüm durumunu yönetme teknikleri veya oturum durumu gibi alternatifler Entity Framework'e özgü değildir, bu nedenle bu öğretici bu konuya ayrıntılı olarak girmez. Daha fazla bilgi için öğreticinin sonundaki bağlantılara bakın.

Ancak, ASP.NET sürüm 4, Web Forms uygulamalarının her ASP.NET geliştiricisinin dikkat etmesi gereken görünüm durumuyla çalışmanın yeni bir yolunu sağlar: ViewStateMode özelliği. Bu yeni özellik, sayfa veya denetim düzeyinde ayarlanabilir ve bir sayfa için görünüm durumunu varsayılan olarak devre dışı bırakmanıza ve yalnızca ihtiyacı olan denetimler için etkinleştirmenize olanak tanır.

Performansın kritik olduğu uygulamalarda, görünüm durumunu her zaman sayfa düzeyinde devre dışı bırakmak ve yalnızca bunu gerektiren denetimler için etkinleştirmek iyi bir uygulamadır. Contoso Üniversitesi sayfalarında görüntüleme durumunun boyutu bu yöntemle önemli ölçüde azaltılamaz, ancak nasıl çalıştığını görmek için Bunu Instructors.aspx sayfasında yapacaksınız. Bu sayfada görüntüleme durumu devre dışı bırakılmış bir Label denetim de dahil olmak üzere birçok denetim vardır. Bu sayfadaki denetimlerin hiçbirinin görüntüleme durumunun etkinleştirilmesi gerekmez. (Denetimin DataKeyNamesGridView özelliği, geri göndermeler arasında tutulması gereken durumu belirtir, ancak bu değerler, özellikten ViewStateMode etkilenmeyen denetim durumunda tutulur.)

Page Yönerge ve Label denetim işaretlemesi şu anda aşağıdaki örneğe benzer:

<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true"
    CodeBehind="Instructors.aspx.cs" Inherits="ContosoUniversity.Instructors" %>
    ...
    <asp:Label ID="ErrorMessageLabel" runat="server" Text="" Visible="false" ViewStateMode="Disabled"></asp:Label> 
    ...

Aşağıdaki değişiklikleri yapın:

  • yönergesine Page ekleyinViewStateMode="Disabled".
  • Denetimden Label kaldırınViewStateMode="Disabled".

İşaretlemesi artık aşağıdaki örneğe benzer:

<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true"
    CodeBehind="Instructors.aspx.cs" Inherits="ContosoUniversity.Instructors" 
    ViewStateMode="Disabled" %>
    ...
    <asp:Label ID="ErrorMessageLabel" runat="server" Text="" Visible="false"></asp:Label> 
    ...

Görünüm durumu artık tüm denetimler için devre dışı bırakıldı. Daha sonra görünüm durumunu kullanması gereken bir denetim eklerseniz, tek yapmanız gereken bu denetimin özniteliğini ViewStateMode="Enabled" eklemektir.

NoTracking Birleştirme seçeneğini kullanma

Nesne bağlamı veritabanı satırlarını aldığında ve bunları temsil eden varlık nesneleri oluşturduğunda, varsayılan olarak nesne durum yöneticisini kullanarak bu varlık nesnelerini de izler. Bu izleme verileri önbellek görevi görür ve varlığı güncelleştirdiğinizde kullanılır. Bir web uygulamasının genellikle kısa süreli nesne bağlam örnekleri olduğundan, sorgular genellikle izlenmesi gerekmeyen veriler döndürür, çünkü bunları okuyan nesne bağlamı, okuduğu varlıkların herhangi biri yeniden kullanılmadan veya güncelleştirilmeden önce atılır.

Entity Framework'te, birleştirme seçeneği ayarlayarak nesne bağlamın varlık nesnelerini izleyip izlemediğini belirtebilirsiniz. Tek tek sorgular veya varlık kümeleri için birleştirme seçeneğini ayarlayabilirsiniz. Bir varlık kümesi için ayarlarsanız, bu, söz konusu varlık kümesi için oluşturulan tüm sorgular için varsayılan birleştirme seçeneğini ayarladığınız anlamına gelir.

Contoso University uygulaması için, depodan eriştiğiniz varlık kümelerinden herhangi biri için izleme gerekmez; bu nedenle, depo sınıfında nesne bağlamı örneği oluştururken bu varlık kümeleri için birleştirme seçeneğini NoTracking olarak ayarlayabilirsiniz. (Bu öğreticide birleştirme seçeneğini ayarlamanın uygulamanın performansı üzerinde belirgin bir etkisi olmayacağına dikkat edin. Bu NoTracking seçenek büyük olasılıkla yalnızca belirli yüksek veri hacmine sahip senaryolarda gözlemlenebilir bir performans geliştirmesi yapar.)

DAL klasöründe SchoolRepository.cs dosyasını açın ve deponun eriştiği varlık kümeleri için birleştirme seçeneğini ayarlayan bir oluşturucu yöntemi ekleyin:

public SchoolRepository()
{
    context.Departments.MergeOption = MergeOption.NoTracking;
    context.InstructorNames.MergeOption = MergeOption.NoTracking;
    context.OfficeAssignments.MergeOption = MergeOption.NoTracking;
}

LINQ Sorgularını Önceden Derleme

Entity Framework'ün belirli ObjectContext bir örneğin ömrü içinde bir Entity SQL sorgusunu ilk kez yürüttüğünde, sorgunun derlenmiş olması biraz zaman alır. Derlemenin sonucu önbelleğe alınır, bu da sorgunun sonraki yürütmelerinin çok daha hızlı olduğu anlamına gelir. LINQ sorguları da benzer bir desen izler, ancak sorguyu derlemek için gereken bazı işlerin sorgu her yürütildiğinde yapılması gerekir. Başka bir deyişle, LINQ sorguları için varsayılan olarak derleme sonuçlarının tümü önbelleğe alınmaz.

Bir nesne bağlamında tekrar tekrar çalıştırmayı beklediğiniz bir LINQ sorgunuz varsa, LINQ sorgusu ilk kez çalıştırıldığında derleme sonuçlarının tümünün önbelleğe alınmasına neden olan kod yazabilirsiniz.

Çizim olarak, bunu sınıfındaki SchoolRepository iki Get yöntem için yapacaksınız; bunlardan biri parametre GetInstructorNames (yöntem) almaz ve biri parametre (GetDepartmentsByAdministratoryöntemi) gerektirir. LinQ sorguları olmadıklarından, şu anda bu yöntemlerin derlenmeleri gerekmez:

public IEnumerable<InstructorName> GetInstructorNames()
{
    return context.InstructorNames.OrderBy("it.FullName").ToList();
}
public IEnumerable<Department> GetDepartmentsByAdministrator(Int32 administrator)
{
    return new ObjectQuery<Department>("SELECT VALUE d FROM Departments as d", context, MergeOption.NoTracking).Include("Person").Where(d => d.Administrator == administrator).ToList();
}

Ancak derlenmiş sorguları deneyebilmeniz için, bunlar aşağıdaki LINQ sorguları olarak yazılmış gibi devam edersiniz:

public IEnumerable<InstructorName> GetInstructorNames()
{
    return (from i in context.InstructorNames orderby i.FullName select i).ToList();
}
public IEnumerable<Department> GetDepartmentsByAdministrator(Int32 administrator)
{
    context.Departments.MergeOption = MergeOption.NoTracking;
    return (from d in context.Departments where d.Administrator == administrator select d).ToList();
}

Bu yöntemlerdeki kodu yukarıda gösterilen kodla değiştirebilir ve devam etmeden önce çalıştığını doğrulamak için uygulamayı çalıştırabilirsiniz. Ancak aşağıdaki yönergeler doğrudan bunların önceden derlenmiş sürümlerini oluşturmaya atlar.

DAL klasöründe bir sınıf dosyası oluşturun, SchoolEntities.cs olarak adlandırın ve mevcut kodu aşağıdaki kodla değiştirin:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Data.Objects;

namespace ContosoUniversity.DAL
{
    public partial class SchoolEntities
    {
        private static readonly Func<SchoolEntities, IQueryable<InstructorName>> compiledInstructorNamesQuery =
            CompiledQuery.Compile((SchoolEntities context) => from i in context.InstructorNames orderby i.FullName select i);

        public IEnumerable<InstructorName> CompiledInstructorNamesQuery()
        {
            return compiledInstructorNamesQuery(this).ToList();
        }

        private static readonly Func<SchoolEntities, Int32, IQueryable<Department>> compiledDepartmentsByAdministratorQuery =
            CompiledQuery.Compile((SchoolEntities context, Int32 administrator) => from d in context.Departments.Include("Person") where d.Administrator == administrator select d);

        public IEnumerable<Department> CompiledDepartmentsByAdministratorQuery(Int32 administrator)
        {
            return compiledDepartmentsByAdministratorQuery(this, administrator).ToList();
        }
    }
}

Bu kod, otomatik olarak oluşturulan nesne bağlam sınıfını genişleten kısmi bir sınıf oluşturur. Kısmi sınıf, sınıfının yöntemini CompiledQuery kullanan Compile iki derlenmiş LINQ sorgusu içerir. Ayrıca sorguları çağırmak için kullanabileceğiniz yöntemler de oluşturur. Bu dosyayı kaydedin ve kapatın.

Ardından SchoolRepository.cs dosyasında, depo sınıfındaki mevcut GetInstructorNames ve GetDepartmentsByAdministrator yöntemlerini, derlenmiş sorguları çağırabilecek şekilde değiştirin:

public IEnumerable<InstructorName> GetInstructorNames()
{
    return context.CompiledInstructorNamesQuery();
}
public IEnumerable<Department> GetDepartmentsByAdministrator(Int32 administrator)
{
    return context.CompiledDepartmentsByAdministratorQuery(administrator);
}

Daha önce olduğu gibi çalıştığını doğrulamak için Departments.aspx sayfasını çalıştırın. GetInstructorNames Yönetici açılan listesini doldurmak için yöntemi çağrılır ve GetDepartmentsByAdministrator hiçbir eğitmenin birden fazla departmanın yöneticisi olmadığını doğrulamak için Güncelleştir'e tıkladığınızda yöntemi çağrılır.

Resim03

Contoso University uygulamasında yalnızca nasıl yapılacağını görmek için sorguları önceden derlediniz; performansı ölçülebilir bir şekilde artıracağından değil. LINQ sorgularının önceden derlenmesi, kodunuza karmaşıklık düzeyi ekler, bu nedenle bunu yalnızca uygulamanızdaki performans sorunlarını temsil eden sorgular için yaptığınızdan emin olun.

Veritabanına Gönderilen Sorguları inceleme

Performans sorunlarını araştırırken, Entity Framework'ün veritabanına gönderdiği tam SQL komutlarını bilmek bazen yararlı olabilir. Bir IQueryable nesneyle çalışıyorsanız, bunu gerçekleştirmenin bir yolu yöntemini kullanmaktır ToTraceString .

SchoolRepository.cs dosyasında, yöntemindeki GetDepartmentsByName kodu aşağıdaki örnekle eşleşecek şekilde değiştirin:

public IEnumerable<Department> GetDepartmentsByName(string sortExpression, string nameSearchString)
{
    ...
    var departments = new ObjectQuery<Department>("SELECT VALUE d FROM Departments AS d", context).OrderBy("it." + sortExpression).Include("Person").Include("Courses").Where(d => d.Name.Contains(nameSearchString));
    string commandText = ((ObjectQuery)departments).ToTraceString();
    return departments.ToList();
}

Değişkenin departments yalnızca bir ObjectQuery türe türe yayınlanması gerekir çünkü Where önceki satırın sonundaki yöntem bir IQueryable nesnesi oluşturur; yöntemi olmadan Where türe dönüştürme gerekli olmaz.

Satırda return bir kesme noktası ayarlayın ve ardından hata ayıklayıcıda Departments.aspx sayfasını çalıştırın. Kesme noktasına gittiğinizde, Yereller penceresindeki değişkeni inceleyin commandText ve metin görselleştiricisini (Değer sütunundaki büyüteç) kullanarak değerini Metin Görselleştiricisi penceresinde görüntüleyin. Bu koddan kaynaklanan SQL komutunun tamamını görebilirsiniz:

Resim08

Alternatif olarak, Visual Studio Ultimate'deki IntelliTrace özelliği, Entity Framework tarafından oluşturulan ve kodunuzu değiştirmenizi ve hatta kesme noktası ayarlamanızı gerektirmeyen SQL komutlarını görüntülemenin bir yolunu sağlar.

Not

Aşağıdaki yordamları yalnızca Visual Studio Ultimate gerçekleştirebilirsiniz.

yöntemindeki GetDepartmentsByName özgün kodu geri yükleyin ve ardından hata ayıklayıcıda Departments.aspx sayfasını çalıştırın.

Visual Studio'da Hata Ayıklama menüsünü, ardından IntelliTrace'i ve ardından IntelliTrace Olayları'nı seçin.

Resim11

IntelliTrace penceresinde Tümünü Kes'e tıklayın.

Resim12

IntelliTrace penceresinde son olayların listesi görüntülenir:

Resim09

ADO.NET satırına tıklayın. Komut metnini gösterecek şekilde genişler:

Resim10

Komut metin dizesinin tamamını Yerel Ayarlar penceresinden panoya kopyalayabilirsiniz.

Basit School veritabanından daha fazla tablo, ilişki ve sütun içeren bir veritabanıyla çalıştığınızı varsayalım. İhtiyacınız olan tüm bilgileri birden çok Join yan tümce içeren tek Select bir deyimde toplayan bir sorgunun verimli çalışamayacak kadar karmaşık hale geldiğini fark edebilirsiniz. Bu durumda sorguyu basitleştirmek için istekli yüklemeden açık yüklemeye geçebilirsiniz.

Örneğin SchoolRepository.cs dosyasındaki yöntemindeki kodu GetDepartmentsByName değiştirmeyi deneyin. Şu anda bu yöntemde ve Courses gezinti özellikleri için Person yöntemleri olan bir nesne sorgunuz vardırInclude. deyimini return , aşağıdaki örnekte gösterildiği gibi açık yükleme gerçekleştiren kodla değiştirin:

public IEnumerable<Department> GetDepartmentsByName(string sortExpression, string nameSearchString)
{
    ...
    var departments = new ObjectQuery<Department>("SELECT VALUE d FROM Departments AS d", context).OrderBy("it." + sortExpression).Where(d => d.Name.Contains(nameSearchString)).ToList();
    foreach (Department d in departments)
    {
        d.Courses.Load();
        d.PersonReference.Load();
    }
    return departments;
}

Hata ayıklayıcıda Departments.aspx sayfasını çalıştırın ve daha önce yaptığınız gibi IntelliTrace penceresini yeniden denetleyin. Şimdi, daha önce tek bir sorgu olduğunda, bunların uzun bir dizisini görürsünüz.

Resim13

Daha önce görüntülediğiniz karmaşık sorguya ne olduğunu görmek için ilk ADO.NET satırına tıklayın.

Resim14

Departmanlar'dan gelen sorgu, yan tümcesi olmayan Join basit Select bir sorgu haline gelmiştir, ancak özgün sorgu tarafından döndürülen her bölüm için iki sorgu kümesi kullanılarak ilgili kursları ve yöneticiyi alan ayrı sorgular tarafından takip edilir.

Not

Gecikmeli yüklemeyi etkin bırakırsanız, burada gördüğünüz desen, aynı sorgunun birçok kez yinelenmesinden kaynaklanabilir. Normalde kaçınmak istediğiniz bir düzen, birincil tablonun her satırı için ilgili verileri yavaş yüklemektir. Tek bir birleştirme sorgusunun verimli olamayacak kadar karmaşık olduğunu doğrulamadığınız sürece, birincil sorguyu istekli yüklemeyi kullanacak şekilde değiştirerek bu gibi durumlarda performansı geliştirebilirsiniz.

Önceden Oluşturulan Görünümler

Bir ObjectContext nesne yeni bir uygulama etki alanında ilk kez oluşturulduğunda, Entity Framework veritabanına erişmek için kullandığı bir sınıf kümesi oluşturur. Bu sınıflara görünüm adı verilir ve çok büyük bir veri modeliniz varsa, bu görünümlerin oluşturulması yeni bir uygulama etki alanı başlatıldıktan sonra web sitesinin ilk sayfa isteğine yanıtını geciktirebilir. Görünümleri çalışma zamanında değil derleme zamanında oluşturarak bu ilk istek gecikmesini azaltabilirsiniz.

Not

Uygulamanızın çok büyük bir veri modeli yoksa veya büyük bir veri modeli varsa ancak IIS geri dönüştürüldikten sonra yalnızca ilk sayfa isteğini etkileyen bir performans sorunuyla ilgilenmiyorsanız, bu bölümü atlayabilirsiniz. Görünümler uygulama etki alanında önbelleğe alındığından, her ObjectContext nesne örneği oluşturduğunuzda görünüm oluşturma işlemi gerçekleşmez. Bu nedenle, uygulamanızı IIS'de sık sık geri dönüştürmediğiniz sürece, önceden oluşturulmuş görünümlerden çok az sayfa isteği yararlanabilirsiniz.

EdmGen.exe komut satırı aracını veya Metin Şablonu Dönüştürme Araç Seti (T4) şablonunu kullanarak görünümleri önceden oluşturabilirsiniz. Bu öğreticide bir T4 şablonu kullanacaksınız.

DAL klasöründe, Metin Şablonu şablonunu kullanarak bir dosya ekleyin (Yüklü Şablonlar listesindeki Genel düğümü altındadır) ve SchoolModel.Views.tt olarak adlandırın. Dosyadaki mevcut kodu aşağıdaki kodla değiştirin:

<#
/***************************************************************************

Copyright (c) Microsoft Corporation. All rights reserved.

THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.

***************************************************************************/
#>

<#
    //
    // TITLE: T4 template to generate views for an EDMX file in a C# project
    //
    // DESCRIPTION:
    // This is a T4 template to generate views in C# for an EDMX file in C# projects.
    // The generated views are automatically compiled into the project's output assembly.
    //
    // This template follows a simple file naming convention to determine the EDMX file to process:
    // - It assumes that [edmx-file-name].Views.tt will process and generate views for [edmx-file-name].EDMX
    // - The views are generated in the code behind file [edmx-file-name].Views.cs
    //
    // USAGE:
    // Do the following to generate views for an EDMX file (e.g. Model1.edmx) in a C# project
    // 1. In Solution Explorer, right-click the project node and choose "Add...Existing...Item" from the context menu
    // 2. Browse to and choose this .tt file to include it in the project 
    // 3. Ensure this .tt file is in the same directory as the EDMX file to process 
    // 4. In Solution Explorer, rename this .tt file to the form [edmx-file-name].Views.tt (e.g. Model1.Views.tt)
    // 5. In Solution Explorer, right-click Model1.Views.tt and choose "Run Custom Tool" to generate the views
    // 6. The views are generated in the code behind file Model1.Views.cs
    //
    // TIPS:
    // If you have multiple EDMX files in your project then make as many copies of this .tt file and rename appropriately
    // to pair each with each EDMX file.
    //
    // To generate views for all EDMX files in the solution, click the "Transform All Templates" button in the Solution Explorer toolbar
    // (its the rightmost button in the toolbar) 
    //
#>
<#
    //
    // T4 template code follows
    //
#>
<#@ template language="C#" hostspecific="true"#>
<#@ include file="EF.Utility.CS.ttinclude"#>
<#@ output extension=".cs" #>
<# 
    // Find EDMX file to process: Model1.Views.tt generates views for Model1.EDMX
    string edmxFileName = Path.GetFileNameWithoutExtension(this.Host.TemplateFile).ToLowerInvariant().Replace(".views", "") + ".edmx";
    string edmxFilePath = Path.Combine(Path.GetDirectoryName(this.Host.TemplateFile), edmxFileName);
    if (File.Exists(edmxFilePath))
    {
        // Call helper class to generate pre-compiled views and write to output
        this.WriteLine(GenerateViews(edmxFilePath));
    }
    else
    {
        this.Error(String.Format("No views were generated. Cannot find file {0}. Ensure the project has an EDMX file and the file name of the .tt file is of the form [edmx-file-name].Views.tt", edmxFilePath));
    }
    
    // All done!
#>

<#+
    private String GenerateViews(string edmxFilePath)
    {
        MetadataLoader loader = new MetadataLoader(this);
        MetadataWorkspace workspace;
        if(!loader.TryLoadAllMetadata(edmxFilePath, out workspace))
        {
            this.Error("Error in the metadata");
            return String.Empty;
        }
            
        String generatedViews = String.Empty;
        try
        {
            using (StreamWriter writer = new StreamWriter(new MemoryStream()))
            {
                StorageMappingItemCollection mappingItems = (StorageMappingItemCollection)workspace.GetItemCollection(DataSpace.CSSpace);

                // Initialize the view generator to generate views in C#
                EntityViewGenerator viewGenerator = new EntityViewGenerator();
                viewGenerator.LanguageOption = LanguageOption.GenerateCSharpCode;
                IList<EdmSchemaError> errors = viewGenerator.GenerateViews(mappingItems, writer);

                foreach (EdmSchemaError e in errors)
                {
                    // log error
                    this.Error(e.Message);
                }

                MemoryStream memStream = writer.BaseStream as MemoryStream;
                generatedViews = Encoding.UTF8.GetString(memStream.ToArray());
            }
        }
        catch (Exception ex)
        {
            // log error
            this.Error(ex.ToString());
        }

        return generatedViews;
    }
#>

Bu kod, şablonla aynı klasörde bulunan ve şablon dosyasıyla aynı ada sahip bir .edmx dosyası için görünümler oluşturur. Örneğin, şablon dosyanızın adı SchoolModel.Views.tt ise SchoolModel.edmx adlı bir veri modeli dosyası arar.

Dosyayı kaydedin, ardından Çözüm Gezgini'da dosyaya sağ tıklayın ve Özel Aracı Çalıştır'ı seçin.

Resim02

Visual Studio, şablonu temel alan SchoolModel.Views.cs adlı görünümleri oluşturan bir kod dosyası oluşturur. (Şablon dosyasını kaydeder kaydetmez Özel Aracı Çalıştır'ı seçmeden önce bile kod dosyasının oluşturulduğunu fark etmiş olabilirsiniz.)

Resim01

Artık uygulamayı çalıştırabilir ve daha önce olduğu gibi çalıştığını doğrulayabilirsiniz.

Önceden oluşturulmuş görünümler hakkında daha fazla bilgi için aşağıdaki kaynaklara bakın:

Bu, Entity Framework kullanan bir ASP.NET web uygulamasında performansı geliştirmeye giriş işlemini tamamlar. Daha fazla bilgi için aşağıdaki kaynaklara bakın:

Sonraki öğreticide, Entity Framework'te sürüm 4'te yeni olan bazı önemli geliştirmeler incelenir.