Zaawansowane scenariusze platformy Entity Framework dla aplikacji internetowej MVC (10 z 10)

Autor : Tom Dykstra

Przykładowa aplikacja internetowa Contoso University pokazuje, jak utworzyć aplikacje ASP.NET MVC 4 przy użyciu programu Entity Framework 5 Code First i Visual Studio 2012. Aby uzyskać informacje na temat serii samouczków, zobacz pierwszy samouczek z serii.

Uwaga

Jeśli napotkasz problem, którego nie możesz rozwiązać, pobierz ukończony rozdział i spróbuj odtworzyć problem. Zazwyczaj rozwiązanie problemu można znaleźć, porównując kod z ukończonym kodem. Aby uzyskać informacje o niektórych typowych błędach i sposobach ich rozwiązywania, zobacz Błędy i obejścia.

W poprzednim samouczku zaimplementowano repozytorium i jednostkę wzorców pracy. W tym samouczku omówiono następujące tematy:

  • Wykonywanie nieprzetworzonych zapytań SQL.
  • Wykonywanie zapytań bez śledzenia.
  • Badanie zapytań wysyłanych do bazy danych.
  • Praca z klasami serwerów proxy.
  • Wyłączanie automatycznego wykrywania zmian.
  • Wyłączanie walidacji podczas zapisywania zmian.
  • Błędy i obejścia

W przypadku większości tych tematów będziesz pracować ze stronami, które zostały już utworzone. Aby użyć nieprzetworzonych aktualizacji sql, utworzysz nową stronę, która aktualizuje liczbę środków na wszystkie kursy w bazie danych:

Zrzut ekranu przedstawiający początkową stronę Aktualizuj środki na kurs. Liczba 2 jest wprowadzana w polu tekstowym.

Aby użyć zapytania bez śledzenia, dodaj nową logikę walidacji do strony Edytowanie działu:

Zrzut ekranu przedstawiający stronę Edycji działu uniwersytetu Contoso z duplikatem komunikatu o błędzie administratora.

Wykonywanie nieprzetworzonych zapytań SQL

Interfejs API Code First platformy Entity Framework zawiera metody, które umożliwiają przekazywanie poleceń SQL bezpośrednio do bazy danych. Do wyboru są następujące opcje:

  • DbSet.SqlQuery Użyj metody dla zapytań, które zwracają typy jednostek. Zwrócone obiekty muszą być typu oczekiwanego przez DbSet obiekt i są automatycznie śledzone przez kontekst bazy danych, chyba że wyłączysz śledzenie. (Zobacz następującą sekcję AsNoTracking dotyczącą metody).
  • Database.SqlQuery Użyj metody dla zapytań, które zwracają typy, które nie są jednostkami. Zwrócone dane nie są śledzone przez kontekst bazy danych, nawet jeśli ta metoda jest używana do pobierania typów jednostek.
  • Użyj polecenia Database.ExecuteSqlCommand dla poleceń innych niż zapytania.

Jedną z zalet korzystania z platformy Entity Framework jest uniknięcie zbyt ścisłego wiązania kodu z określoną metodą przechowywania danych. Robi to, generując zapytania i polecenia SQL dla Ciebie, co również zwalnia Cię od konieczności samodzielnego pisania. Istnieją jednak wyjątkowe scenariusze, gdy trzeba uruchomić określone zapytania SQL utworzone ręcznie, a te metody umożliwiają obsługę takich wyjątków.

Tak jak zawsze w przypadku wykonywania poleceń SQL w aplikacji internetowej, należy podjąć środki ostrożności, aby chronić witrynę przed atakami polegającymi na wstrzyknięciu kodu SQL. Jednym ze sposobów wykonania tej czynności jest użycie sparametryzowanych zapytań w celu upewnienia się, że ciągi przesłane przez stronę internetową nie mogą być interpretowane jako polecenia SQL. W tym samouczku użyjesz sparametryzowanych zapytań podczas integrowania danych wejściowych użytkownika z zapytaniem.

Wywoływanie zapytania zwracającego jednostki

Załóżmy, że chcesz, GenericRepository aby klasa zapewniała dodatkową elastyczność filtrowania i sortowania bez konieczności tworzenia klasy pochodnej przy użyciu dodatkowych metod. Jednym ze sposobów osiągnięcia tego celu byłoby dodanie metody akceptującej zapytanie SQL. Następnie można określić dowolny rodzaj filtrowania lub sortowania w kontrolerze, na przykład klauzulę Where , która zależy od sprzężeń lub podquerii. W tej sekcji dowiesz się, jak zaimplementować taką metodę.

Utwórz metodę GetWithRawSql , dodając następujący kod do pliku GenericRepository.cs:

public virtual IEnumerable<TEntity> GetWithRawSql(string query, params object[] parameters)
{
    return dbSet.SqlQuery(query, parameters).ToList();
}

W pliku CourseController.cs wywołaj nową metodę z Details metody, jak pokazano w poniższym przykładzie:

public ActionResult Details(int id)
{
    var query = "SELECT * FROM Course WHERE CourseID = @p0";
    return View(unitOfWork.CourseRepository.GetWithRawSql(query, id).Single());
}

W takim przypadku można było użyć GetByID metody , ale używasz GetWithRawSql metody w celu sprawdzenia, czy GetWithRawSQL metoda działa.

Uruchom stronę Szczegóły, aby sprawdzić, czy wybrane zapytanie działa (wybierz kartę Kurs , a następnie pozycję Szczegóły dla jednego kursu).

Zrzut ekranu przedstawiający stronę Szczegóły uniwersytetu Contoso.

Wywoływanie zapytania zwracającego inne typy obiektów

Wcześniej utworzono siatkę statystyk uczniów dla strony Informacje, która pokazała liczbę uczniów dla każdej daty rejestracji. Kod, który wykonuje to w pliku HomeController.cs , używa LINQ:

var data = from student in db.Students
           group student by student.EnrollmentDate into dateGroup
           select new EnrollmentDateGroup()
           {
               EnrollmentDate = dateGroup.Key,
               StudentCount = dateGroup.Count()
           };

Załóżmy, że chcesz napisać kod, który pobiera te dane bezpośrednio w języku SQL, zamiast używać LINQ. Aby to zrobić, należy uruchomić zapytanie zwracające coś innego niż obiekty jednostki, co oznacza, że musisz użyć Database.SqlQuery metody .

W pliku HomeController.cs zastąp instrukcję LINQ w About metodzie następującym kodem:

var query = "SELECT EnrollmentDate, COUNT(*) AS StudentCount "
    + "FROM Person "
    + "WHERE EnrollmentDate IS NOT NULL "
    + "GROUP BY EnrollmentDate";
var data = db.Database.SqlQuery<EnrollmentDateGroup>(query);

Uruchom stronę Informacje. Wyświetla te same dane, które zostały wcześniej.

Zrzut ekranu przedstawiający stronę Contoso University About (Informacje o uniwersytecie contoso).

Wywoływanie zapytania aktualizacji

Załóżmy, że administratorzy contoso University chcą mieć możliwość przeprowadzania zbiorczych zmian w bazie danych, takich jak zmiana liczby środków na każdy kurs. Jeśli uniwersytet ma dużą liczbę kursów, byłoby nieefektywne, aby pobrać je wszystkie jako jednostki i zmienić je indywidualnie. W tej sekcji zaimplementujesz stronę internetową, która umożliwia użytkownikowi określenie czynnika, za pomocą którego należy zmienić liczbę środków dla wszystkich kursów, a następnie wprowadzisz zmianę, wykonując instrukcję SQL UPDATE . Strona internetowa będzie wyglądać podobnie do poniższej ilustracji:

Zrzut ekranu przedstawiający początkową stronę Aktualizuj środki na kurs. Liczba 2 jest wprowadzana w polu tekstowym.

W poprzednim samouczku użyto repozytorium ogólnego do odczytywania i aktualizowania Course jednostek w kontrolerze Course . W przypadku tej operacji zbiorczej aktualizacji należy utworzyć nową metodę repozytorium, która nie znajduje się w repozytorium ogólnym. W tym celu utworzysz dedykowaną CourseRepository klasę, która pochodzi z GenericRepository klasy .

W folderze DAL utwórz plik CourseRepository.cs i zastąp istniejący kod następującym kodem:

using System;
using ContosoUniversity.Models;

namespace ContosoUniversity.DAL
{
    public class CourseRepository : GenericRepository<Course>
    {
        public CourseRepository(SchoolContext context)
            : base(context)
        {
        }

        public int UpdateCourseCredits(int multiplier)
        {
            return context.Database.ExecuteSqlCommand("UPDATE Course SET Credits = Credits * {0}", multiplier);
        }

    }
}

W pliku UnitOfWork.cs zmień Course typ repozytorium z GenericRepository<Course> na CourseRepository:

private CourseRepository courseRepository;
public CourseRepository CourseRepository
{
    get
    {

        if (this.courseRepository == null)
        {
            this.courseRepository = new CourseRepository(context);
        }
        return courseRepository;
    }
}

W pliku CourseController.cs dodaj metodę UpdateCourseCredits :

public ActionResult UpdateCourseCredits(int? multiplier)
{
    if (multiplier != null)
    {
        ViewBag.RowsAffected = unitOfWork.CourseRepository.UpdateCourseCredits(multiplier.Value);
    }
    return View();
}

Ta metoda będzie używana zarówno dla metody , jak HttpGet i HttpPost. Po uruchomieniu HttpGetUpdateCourseCredits metody zmienna będzie mieć wartość null, multiplier a widok wyświetli puste pole tekstowe i przycisk przesyłania, jak pokazano na poprzedniej ilustracji.

Po kliknięciu przycisku Aktualizuj i uruchomieniu HttpPostmultiplier metody wartość zostanie wprowadzona w polu tekstowym. Następnie kod wywołuje metodę repozytorium UpdateCourseCredits , która zwraca liczbę wierszy, których dotyczy problem, i ta wartość jest przechowywana w ViewBag obiekcie. Gdy widok odbiera liczbę wierszy ViewBag , których dotyczy ten obiekt, wyświetla ten numer zamiast pola tekstowego i przycisk przesyłania, jak pokazano na poniższej ilustracji:

Zrzut ekranu przedstawiający stronę kredytów na kursie firmy Contoso University Update.

Utwórz widok w folderze Views\Course dla strony Aktualizuj środki na kurs:

Zrzut ekranu przedstawiający okno dialogowe Dodawanie widoku. Środki na kurs aktualizacji są wprowadzane w polu tekstowym Nazwa widoku.

W pliku Views\Course\UpdateCourseCredits.cshtml zastąp kod szablonu następującym kodem:

@model ContosoUniversity.Models.Course

@{
    ViewBag.Title = "UpdateCourseCredits";
}

<h2>Update Course Credits</h2>

@if (ViewBag.RowsAffected == null)
{
    using (Html.BeginForm())
    {
        <p>
            Enter a number to multiply every course's credits by: @Html.TextBox("multiplier")
        </p>
        <p>
            <input type="submit" value="Update" />
        </p>
    }
}
@if (ViewBag.RowsAffected != null)
{
    <p>
        Number of rows updated: @ViewBag.RowsAffected
    </p>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>

Uruchom metodę UpdateCourseCredits , wybierając kartę Kursy , a następnie dodając ciąg "/UpdateCourseCredits" na końcu adresu URL na pasku adresu przeglądarki (na przykład: http://localhost:50205/Course/UpdateCourseCredits). Wprowadź liczbę w polu tekstowym:

Zrzut ekranu przedstawiający początkową stronę Aktualizuj środki na kurs z numerem 2 wprowadzonym w polu tekstowym.

Kliknij przycisk Update (Aktualizuj). Zostanie wyświetlona liczba wierszy, których dotyczy problem:

Zrzut ekranu przedstawiający stronę Aktualizuj środki na kurs ze zaktualizowaną liczbą wierszy.

Kliknij przycisk Wstecz do listy, aby wyświetlić listę kursów ze zmienioną liczbą środków.

Zrzut ekranu przedstawiający stronę Indeks kursów. Lista kursów jest wyświetlana ze zmienioną liczbą środków.

Aby uzyskać więcej informacji na temat nieprzetworzonych zapytań SQL, zobacz Nieprzetworzone zapytania SQL w blogu zespołu platformy Entity Framework.

zapytania No-Tracking

Gdy kontekst bazy danych pobiera wiersze bazy danych i tworzy obiekty jednostki, które je reprezentują, domyślnie śledzi, czy jednostki w pamięci są zsynchronizowane z obiektami w bazie danych. Dane w pamięci działają jako pamięć podręczna i są używane podczas aktualizowania jednostki. Buforowanie jest często niepotrzebne w aplikacji internetowej, ponieważ wystąpienia kontekstowe są zwykle krótkotrwałe (nowy jest tworzony i usuwany dla każdego żądania) oraz kontekst, który odczytuje jednostkę, jest zwykle usuwany, zanim ta jednostka zostanie ponownie użyta.

Można określić, czy kontekst śledzi obiekty jednostki dla zapytania przy użyciu AsNoTracking metody . Typowe scenariusze, w których warto to zrobić, obejmują następujące czynności:

  • Zapytanie pobiera tak dużą ilość danych, które wyłączają śledzenie, co może znacznie zwiększyć wydajność.
  • Chcesz dołączyć jednostkę, aby ją zaktualizować, ale wcześniej pobrano tę samą jednostkę w innym celu. Ponieważ jednostka jest już śledzona przez kontekst bazy danych, nie można dołączyć jednostki, którą chcesz zmienić. Jednym ze sposobów zapobiegania temu jest użycie AsNoTracking opcji z wcześniejszym zapytaniem.

W tej sekcji zaimplementujesz logikę biznesową, która ilustruje drugą z tych scenariuszy. W szczególności wymusisz regułę biznesową, która mówi, że instruktor nie może być administratorem więcej niż jednego działu.

W pliku DepartmentController.cs dodaj nową metodę, którą można wywołać z Edit metod i Create , aby upewnić się, że żadne dwa działy nie mają tego samego administratora:

private void ValidateOneAdministratorAssignmentPerInstructor(Department department)
{
    if (department.PersonID != null)
    {
        var duplicateDepartment = db.Departments
            .Include("Administrator")
            .Where(d => d.PersonID == department.PersonID)
            .FirstOrDefault();
        if (duplicateDepartment != null && duplicateDepartment.DepartmentID != department.DepartmentID)
        {
            var errorMessage = String.Format(
                "Instructor {0} {1} is already administrator of the {2} department.",
                duplicateDepartment.Administrator.FirstMidName,
                duplicateDepartment.Administrator.LastName,
                duplicateDepartment.Name);
            ModelState.AddModelError(string.Empty, errorMessage);
        }
    }
}

Dodaj kod w bloku HttpPostEdit metody , aby wywołać tę nową metodę, try jeśli nie ma błędów walidacji. Blok try wygląda teraz jak w poniższym przykładzie:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(
   [Bind(Include = "DepartmentID, Name, Budget, StartDate, RowVersion, PersonID")]
    Department department)
{
   try
   {
      if (ModelState.IsValid)
      {
         ValidateOneAdministratorAssignmentPerInstructor(department);
      }

      if (ModelState.IsValid)
      {
         db.Entry(department).State = EntityState.Modified;
         db.SaveChanges();
         return RedirectToAction("Index");
      }
   }
   catch (DbUpdateConcurrencyException ex)
   {
      var entry = ex.Entries.Single();
      var clientValues = (Department)entry.Entity;

Uruchom stronę Edytowanie działu i spróbuj zmienić administratora działu na instruktora, który jest już administratorem innego działu. Zostanie wyświetlony oczekiwany komunikat o błędzie:

Zrzut ekranu przedstawiający stronę Edytowanie działu z duplikatem komunikatu o błędzie administratora.

Teraz ponownie uruchom stronę Edytuj dział i tym razem zmień kwotę budżetu . Po kliknięciu przycisku Zapisz zobaczysz stronę błędu:

Zrzut ekranu przedstawiający stronę Edytowanie działu z komunikatem o błędzie menedżera stanu obiektu.

Komunikat o błędzie wyjątku to "An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key." Stało się to z powodu następującej sekwencji zdarzeń:

  • Metoda Edit wywołuje metodę ValidateOneAdministratorAssignmentPerInstructor , która pobiera wszystkie działy, które mają kim Abercrombie jako administratora. To powoduje, że departament angielski jest odczytywany. Ponieważ jest to dział edytowany, nie zgłoszono żadnego błędu. W wyniku tej operacji odczytu jednostka działu angielskiego, która została odczytowana z bazy danych, jest teraz śledzona przez kontekst bazy danych.
  • Metoda Edit próbuje ustawić flagę Modified w jednostce działu angielskiego utworzonej przez binder modelu MVC, ale kończy się to niepowodzeniem, ponieważ kontekst już śledzi jednostkę dla działu angielskiego.

Jednym z rozwiązań tego problemu jest zachowanie kontekstu przed śledzeniem jednostek działu pamięci pobranych przez zapytanie sprawdzania poprawności. Nie ma żadnej wady w tym celu, ponieważ nie będziesz aktualizować tej jednostki ani odczytywać jej ponownie w sposób, który skorzystałby z buforowania w pamięci.

W pliku DepartmentController.cs w metodzie ValidateOneAdministratorAssignmentPerInstructor określ brak śledzenia, jak pokazano poniżej:

var duplicateDepartment = db.Departments
   .Include("Administrator")
   .Where(d => d.PersonID == department.PersonID)
   .AsNoTracking()
   .FirstOrDefault();

Powtórz próbę edytowania kwoty budżetu działu. Tym razem operacja zakończy się pomyślnie, a witryna zostanie zwrócona zgodnie z oczekiwaniami na stronie Indeks działów z wyświetloną poprawioną wartością budżetu.

Badanie zapytań wysyłanych do bazy danych

Czasami warto zobaczyć rzeczywiste zapytania SQL wysyłane do bazy danych. W tym celu możesz zbadać zmienną zapytania w debugerze lub wywołać metodę zapytania ToString . Aby to wypróbować, przyjrzysz się prostemu zapytaniu, a następnie przyjrzysz się temu, co się z nim dzieje, dodając opcje takie chętne do ładowania, filtrowania i sortowania.

W obszarze Controllers/CourseController zastąp metodę Index następującym kodem:

public ViewResult Index()
{
    var courses = unitOfWork.CourseRepository.Get();
    return View(courses.ToList());
}

Teraz ustaw punkt przerwania w pliku GenericRepository.cs w return query.ToList(); instrukcjach i return orderBy(query).ToList(); metody Get . Uruchom projekt w trybie debugowania i wybierz stronę Indeks kursu. Gdy kod osiągnie punkt przerwania, sprawdź zmienną query . Zostanie wyświetlone zapytanie wysyłane do SQL Server. Jest to prosta Select instrukcja:

{SELECT 
[Extent1].[CourseID] AS [CourseID], 
[Extent1].[Title] AS [Title], 
[Extent1].[Credits] AS [Credits], 
[Extent1].[DepartmentID] AS [DepartmentID]
FROM [Course] AS [Extent1]}

Zrzut ekranu przedstawiający kartę Przykładowe repozytorium ogólne aplikacji internetowej. Wybrano zmienną kwerendy.

Zapytania mogą być zbyt długie, aby wyświetlać je w oknach debugowania w programie Visual Studio. Aby wyświetlić całe zapytanie, możesz skopiować wartość zmiennej i wkleić ją do edytora tekstów:

Zrzut ekranu przedstawiający wartość zmiennej z menu rozwijanym wyświetlanym po jej wybraniu. Opcja Kopiuj wartość jest wyróżniona.

Teraz dodasz listę rozwijaną do strony Indeks kursu, aby użytkownicy mogli filtrować dla określonego działu. Posortujesz kursy według tytułu i określisz chętne Department ładowanie dla właściwości nawigacji. W pliku CourseController.cs zastąp metodę Index następującym kodem:

public ActionResult Index(int? SelectedDepartment)
{
    var departments = unitOfWork.DepartmentRepository.Get(
        orderBy: q => q.OrderBy(d => d.Name));
    ViewBag.SelectedDepartment = new SelectList(departments, "DepartmentID", "Name", SelectedDepartment);

    int departmentID = SelectedDepartment.GetValueOrDefault(); 
    return View(unitOfWork.CourseRepository.Get(
        filter: d => !SelectedDepartment.HasValue || d.DepartmentID == departmentID,
        orderBy: q => q.OrderBy(d => d.CourseID),
        includeProperties: "Department"));
}

Metoda odbiera wybraną wartość listy rozwijanej w parametrze SelectedDepartment . Jeśli nic nie zostanie wybrane, ten parametr będzie mieć wartość null.

Kolekcja SelectList zawierająca wszystkie działy jest przekazywana do widoku listy rozwijanej. Parametry przekazane do konstruktora SelectList określają nazwę pola wartości, nazwę pola tekstowego i wybrany element.

Get W przypadku metody Course repozytorium kod określa wyrażenie filtru, kolejność sortowania i chętne ładowanie właściwości Department nawigacji. Wyrażenie filtru zawsze zwraca wartość true , jeśli nic nie jest zaznaczone na liście rozwijanej (czyli SelectedDepartment ma wartość null).

W pliku Views\Course\Index.cshtml bezpośrednio przed tagiem otwierania table dodaj następujący kod, aby utworzyć listę rozwijaną i przycisk przesyłania:

@using (Html.BeginForm())
{
    <p>Select Department: @Html.DropDownList("SelectedDepartment","All")   
    <input type="submit" value="Filter" /></p>
}

Po ustawieniu punktów przerwania w GenericRepository klasie uruchom stronę Indeks kursu. Kontynuuj przez pierwsze dwa razy, że kod trafia do punktu przerwania, aby strona jest wyświetlana w przeglądarce. Wybierz dział z listy rozwijanej, a następnie kliknij pozycję Filtruj:

Zrzut ekranu przedstawiający stronę Indeks kursu z wybraną wybraną działem ekonomii.

Tym razem pierwszy punkt przerwania będzie dotyczyć zapytań działów dla listy rozwijanej. Pomiń tę i wyświetl zmienną query przy następnym osiągnięciu punktu przerwania, aby zobaczyć, jak Course wygląda teraz zapytanie. Zobaczysz coś podobnego do następującego:

{SELECT 
[Extent1].[CourseID] AS [CourseID], 
[Extent1].[Title] AS [Title], 
[Extent1].[Credits] AS [Credits], 
[Extent1].[DepartmentID] AS [DepartmentID], 
[Extent2].[DepartmentID] AS [DepartmentID1], 
[Extent2].[Name] AS [Name], 
[Extent2].[Budget] AS [Budget], 
[Extent2].[StartDate] AS [StartDate], 
[Extent2].[PersonID] AS [PersonID], 
[Extent2].[Timestamp] AS [Timestamp]
FROM  [Course] AS [Extent1]
INNER JOIN [Department] AS [Extent2] ON [Extent1].[DepartmentID] = [Extent2].[DepartmentID]
WHERE (@p__linq__0 IS NULL) OR ([Extent1].[DepartmentID] = @p__linq__1)}

Zobaczysz, że zapytanie jest teraz zapytaniem JOIN , które ładuje Department dane wraz z Course danymi i że zawiera klauzulę WHERE .

Praca z klasami serwerów proxy

Gdy program Entity Framework tworzy wystąpienia jednostek (na przykład podczas wykonywania zapytania), często tworzy je jako wystąpienia dynamicznie wygenerowanego typu pochodnego, który działa jako serwer proxy jednostki. Ten serwer proxy zastępuje niektóre właściwości wirtualne jednostki, aby wstawić punkty zaczepienia do wykonywania akcji automatycznie po korzystaniu z właściwości. Na przykład ten mechanizm służy do obsługi leniwego ładowania relacji.

W większości przypadków nie trzeba pamiętać o tym używaniu serwerów proxy, ale istnieją wyjątki:

  • W niektórych scenariuszach warto uniemożliwić programowi Entity Framework tworzenie wystąpień serwera proxy. Na przykład serializowanie wystąpień innych niż proxy może być bardziej wydajne niż serializowanie wystąpień serwera proxy.
  • Podczas tworzenia wystąpienia klasy jednostki przy użyciu new operatora nie otrzymujesz wystąpienia serwera proxy. Oznacza to, że nie uzyskujesz funkcji, takich jak leniwe ładowanie i automatyczne śledzenie zmian. Jest to zwykle w porządku; zwykle nie trzeba ładować się z opóźnieniem, ponieważ tworzysz nową jednostkę, która nie znajduje się w bazie danych, i zwykle nie potrzebujesz śledzenia zmian, jeśli jawnie oznaczasz jednostkę jako Added. Jeśli jednak potrzebujesz opóźnionego ładowania i potrzebujesz śledzenia zmian, możesz utworzyć nowe wystąpienia jednostek z serwerami proxy przy użyciu Create metody DbSet klasy .
  • Możesz chcieć uzyskać rzeczywisty typ jednostki z typu serwera proxy. Możesz użyć GetObjectType metody ObjectContext klasy, aby uzyskać rzeczywisty typ jednostki wystąpienia typu serwera proxy.

Aby uzyskać więcej informacji, zobacz Artykuł Praca z serwerami proxy w blogu zespołu platformy Entity Framework.

Wyłączanie automatycznego wykrywania zmian

Struktura Entity Framework określa sposób zmiany jednostki (i dlatego aktualizacje muszą być wysyłane do bazy danych) przez porównanie bieżących wartości jednostki z oryginalnymi wartościami. Oryginalne wartości są przechowywane, gdy jednostka została zapytana lub dołączona. Niektóre metody, które powodują automatyczne wykrywanie zmian, są następujące:

  • DbSet.Find
  • DbSet.Local
  • DbSet.Remove
  • DbSet.Add
  • DbSet.Attach
  • DbContext.SaveChanges
  • DbContext.GetValidationErrors
  • DbContext.Entry
  • DbChangeTracker.Entries

Jeśli śledzisz dużą liczbę jednostek i wielokrotnie wywołujesz jedną z tych metod w pętli, możesz uzyskać znaczne ulepszenia wydajności, tymczasowo wyłączając automatyczne wykrywanie zmian przy użyciu właściwości AutoDetectChangesEnabled . Aby uzyskać więcej informacji, zobacz Automatyczne wykrywanie zmian.

Wyłączanie walidacji podczas zapisywania zmian

Po wywołaniu SaveChanges metody program Entity Framework domyślnie weryfikuje dane we wszystkich właściwościach wszystkich zmienionych jednostek przed zaktualizowaniem bazy danych. Jeśli zaktualizowano dużą liczbę jednostek, a dane zostały już zweryfikowane, ta praca jest niepotrzebna i proces zapisywania zmian zajmuje mniej czasu, tymczasowo wyłączając walidację. Można to zrobić przy użyciu właściwości ValidateOnSaveEnabled . Aby uzyskać więcej informacji, zobacz Walidacja.

Podsumowanie

Spowoduje to ukończenie tej serii samouczków dotyczących korzystania z platformy Entity Framework w aplikacji ASP.NET MVC. Linki do innych zasobów platformy Entity Framework można znaleźć na mapie zawartości dostępu do danych ASP.NET.

Aby uzyskać więcej informacji na temat wdrażania aplikacji internetowej po jej skompilowaniu, zobacz ASP.NET Mapowanie zawartości wdrożenia w bibliotece MSDN.

Aby uzyskać informacje o innych tematach związanych z mvC, takimi jak uwierzytelnianie i autoryzacja, zobacz zalecane zasoby MVC.

Podziękowania

  • Tom Dykstra napisał oryginalną wersję tego samouczka i jest starszym pisarzem programowania w zespole zawartości platformy i narzędzi firmy Microsoft.
  • Rick Anderson ( twitter @RickAndMSFT) współtworzył ten samouczek i wykonał większość pracy, aktualizując ją dla EF 5 i MVC 4. Rick jest starszym pisarzem programowania dla firmy Microsoft koncentrującym się na platformie Azure i MVC.
  • Rowan Miller i inni członkowie zespołu Entity Framework pomogli w przeglądach kodu i pomogli debugować wiele problemów z migracjami, które pojawiły się podczas aktualizowania samouczka dotyczącego platformy EF 5.

VB

Po utworzeniu samouczka udostępniliśmy wersje języka C# i VB ukończonego projektu pobierania. Dzięki tej aktualizacji udostępniamy projekt do pobrania w języku C# dla każdego rozdziału, aby ułatwić rozpoczęcie pracy w dowolnym miejscu serii, ale ze względu na ograniczenia czasowe i inne priorytety nie zrobiliśmy tego w języku VB. Jeśli utworzysz projekt VB przy użyciu tych samouczków i chcesz udostępnić go innym osobom, daj nam znać.

Błędy i obejścia

Nie można utworzyć/skopiować w tle

Komunikat o błędzie:

Nie można utworzyć/skopiować kopii w tle "DotNetOpenAuth.OpenId", gdy ten plik już istnieje.

Rozwiązanie:

Poczekaj kilka sekund i odśwież stronę.

Update-Database nie rozpoznano

Komunikat o błędzie:

Termin "Update-Database" nie jest rozpoznawany jako nazwa polecenia cmdlet, funkcji, pliku skryptu lub programu możliwego do działania. Sprawdź pisownię nazwy lub jeśli ścieżka została dołączona, sprawdź, czy ścieżka jest poprawna i spróbuj ponownie.(Z Update-Database polecenia w PMC.)

Rozwiązanie:

Zamknij program Visual Studio. Otwórz ponownie projekt i spróbuj ponownie.

Walidacja nie powiodła się

Komunikat o błędzie:

Walidacja nie powiodła się dla co najmniej jednej jednostki. Aby uzyskać więcej informacji, zobacz właściwość "EntityValidationErrors". (Z Update-Database polecenia w PMC.)

Rozwiązanie:

Jedną z przyczyn tego problemu są błędy walidacji po uruchomieniu Seed metody. Aby uzyskać porady dotyczące debugowania metody, zobacz Seeding and Debugging Entity Framework (EF) DBs (Wypełnianie i debugowanie baz danych platformy Entity Framework (EF).Seed

Błąd HTTP 500.19

Komunikat o błędzie:

Błąd HTTP 500.19 — wewnętrzny błąd serwera
Nie można uzyskać dostępu do żądanej strony, ponieważ powiązane dane konfiguracji dla strony są nieprawidłowe.

Rozwiązanie:

Jednym ze sposobów uzyskania tego błędu jest posiadanie wielu kopii rozwiązania, z których każdy korzysta z tego samego numeru portu. Ten problem można zwykle rozwiązać, zamykając wszystkie wystąpienia programu Visual Studio, a następnie ponownie uruchamiając projekt, nad którym pracujesz. Jeśli to nie zadziała, spróbuj zmienić numer portu. Kliknij prawym przyciskiem myszy plik projektu, a następnie kliknij polecenie właściwości. Wybierz kartę Sieć Web , a następnie zmień numer portu w polu tekstowym Adres URL projektu .

Błąd podczas lokalizowania wystąpienia SQL Server

Komunikat o błędzie:

Podczas nawiązywania połączenia z serwerem SQL wystąpił błąd dotyczący sieci lub wystąpienia. Serwer nie został znaleziony lub był niedostępny. Sprawdź, czy nazwa wystąpienia jest prawidłowa oraz czy program SQL Server skonfigurowano tak, aby zezwalał na połączenia zdalne. (dostawca: interfejsy sieciowe SQL, błąd: 26 — Błąd podczas lokalizowania określonego serwera/wystąpienia)

Rozwiązanie:

Sprawdź parametry połączenia. Jeśli baza danych została ręcznie usunięta, zmień nazwę bazy danych w ciągu konstrukcji.