Udostępnij za pośrednictwem


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

Autor: Tom Dykstra

Przykładowa aplikacja internetowa Contoso University pokazuje, jak tworzyć 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 większości tych tematów będziesz pracować z utworzonymi stronami. Aby użyć pierwotnego kodu SQL do zbiorczego aktualizowania, należy utworzyć 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, do strony Edycja działu dodasz nową logikę walidacji:

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

Wykonywanie nieprzetworzonych zapytań SQL

Interfejs API Code First programu 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ą one 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 używasz tej metody do pobierania typów jednostek.
  • Użyj polecenia Database.ExecuteSqlCommand dla poleceń innych niż zapytania.

Jedną z zalet korzystania z platformy Entity Framework jest unikanie zbyt ścisłego wiązania kodu z określoną metodą przechowywania danych. Robi to przez wygenerowanie zapytań SQL i poleceń dla Ciebie, co pozwala również uwolnić cię od konieczności samodzielnego pisania ich. Istnieją jednak wyjątkowe scenariusze, w których trzeba uruchamiać 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 na to 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 z dodatkowymi metodami. Jednym ze sposobów osiągnięcia tego celu jest dodanie metody akceptującej zapytanie SQL. Następnie można określić dowolny rodzaj filtrowania lub sortowania w kontrolerze, na przykład Where klauzulę, która zależy od sprzężeń lub podzapytania. W tej sekcji zobaczysz, jak zaimplementować taką metodę.

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

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

W 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ę Contoso University Details.

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 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 należy użyć Database.SqlQuery metody .

W HomeController.cs zastąp instrukcję LINQ w metodzie About 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 platformy Contoso University chcą mieć możliwość przeprowadzania zbiorczych zmian w bazie danych, takich jak zmiana liczby środków na każdy kurs. Jeśli uczelnia ma dużą liczbę kursów, byłoby nieefektywne pobranie ich wszystkich jako jednostek i zmiana ich indywidualnie. W tej sekcji zaimplementujesz stronę internetową, która umożliwia użytkownikowi określenie współczynnika, za pomocą którego można zmienić liczbę środków na wszystkie kursy, 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 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 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 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 HttpGet UpdateCourseCredits metody zmienna multiplier będzie mieć wartość null, a widok wyświetli puste pole tekstowe i przycisk przesyłania, jak pokazano na poprzedniej ilustracji.

Po kliknięciu przycisku Aktualizuj i uruchomieniu multiplier HttpPost metody zostanie wprowadzona wartość 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, których dotyczy problem w ViewBag obiekcie, 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 kurs aktualizacji uniwersytetu Firmy Contoso.

Utwórz widok w folderze Views\Course na stronie Aktualizowanie środków na kurs:

Zrzut ekranu przedstawiający okno dialogowe Dodawanie widoku. Aktualizacja środków na kurs jest wprowadzana 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 liczbą 2 wprowadzoną w polu tekstowym.

Kliknij 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 z poprawioną liczbą kredytów.

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

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

Zapytania bez śledzenia

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 elementami 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 kontekstu są zwykle krótkotrwałe (nowy jest tworzony i usuwany dla każdego żądania) oraz kontekst, który odczytuje jednostkę, jest zwykle usuwany przed ponownym użyciu tej jednostki.

Można określić, czy kontekst śledzi obiekty jednostek 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, że wyłączenie śledzenia 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, aby temu zapobiec, 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 DepartmentController.cs dodaj nową metodę, którą można wywołać z Edit metod i Create , aby upewnić się, że żaden z dwóch działów nie ma 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 try bloku HttpPost Edit metody , aby wywołać tę nową metodę, 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ę Edycja 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 zduplikowany komunikat o błędzie administratora.

Teraz ponownie uruchom stronę Edycja działu 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." Wystąpił z powodu następującej sekwencji zdarzeń:

  • Metoda Edit wywołuje metodę ValidateOneAdministratorAssignmentPerInstructor , która pobiera wszystkie działy z Kim Abercrombie jako administrator. To powoduje, że departament angielski jest odczytywany. Ponieważ jest to edytowany dział, nie jest zgłaszany żaden błąd. 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 w pamięci pobranych przez zapytanie sprawdzania poprawności. Nie ma żadnej niekorzystnej sytuacji w tym celu, ponieważ nie będziesz aktualizować tej jednostki ani odczytywać jej ponownie w sposób, który skorzysta z buforowania w pamięci.

W 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 zwróci wartość 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 wypróbować tę metodę, przyjrzysz się prostemu zapytaniu, a następnie przyjrzymy się temu, co się stanie, dodając opcje takie chętne do ładowania, filtrowania i sortowania.

W pliku 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 GenericRepository.cs w return query.ToList(); instrukcjach Get i return orderBy(query).ToList(); metody . 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 programu 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 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.

SelectList Kolekcja 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 dla Department właściwości nawigacji. Wyrażenie filtru zawsze zwraca true wartość, 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. Przejdź przez pierwsze dwa razy, gdy kod osiągnie punkt przerwania, tak aby strona jest wyświetlana w przeglądarce. Wybierz dział z listy rozwijanej i kliknij pozycję Filtr:

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

Tym razem pierwszym punktem przerwania będzie zapytanie dla działów dla listy rozwijanej. Pomiń tę zmienną query i wyświetl zmienną 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)}

Widać, ż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 generowanego typu pochodnego, który działa jako serwer proxy dla jednostki. Ten serwer proxy zastępuje niektóre właściwości wirtualne jednostki w celu wstawiania punktów 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.

Przez większość czasu nie musisz pamiętać o tym używaniu serwerów proxy, ale istnieją wyjątki:

  • W niektórych scenariuszach możesz 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 uzyskujesz 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 potrzebujesz leniwego ładowania, ponieważ tworzysz nową jednostkę, która nie znajduje się w bazie danych, i zwykle nie potrzebujesz śledzenia zmian, jeśli jawnie oznaczysz 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 Praca z serwerami proxy w blogu zespołu programu Entity Framework.

Wyłączanie automatycznego wykrywania zmian

Program Entity Framework określa, w jaki sposób jednostka uległa zmianie (i w związku z tym które aktualizacje muszą być wysyłane do bazy danych), porównując bieżące wartości jednostki z oryginalnymi wartościami. Oryginalne wartości są przechowywane podczas wykonywania zapytań lub dołączania jednostki. 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

Podczas wywoływania 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 i już zweryfikowano dane, ta praca jest niepotrzebna i możesz sprawić, że proces zapisywania zmian zajmie 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

Ta seria samouczków dotyczących korzystania z platformy Entity Framework w aplikacji MVC ASP.NET. Linki do innych zasobów programu 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 mapa zawartości wdrożenia w bibliotece MSDN.

Aby uzyskać informacje o innych tematach dotyczących wzorca MVC, takich jak uwierzytelnianie i autoryzacja, zobacz zalecane zasoby MVC.

Podziękowania

  • Tom Dykstra napisał oryginalną wersję tego samouczka i jest starszym pisarzem programowania w zespole ds. zawartości Platforma Microsoft Web i narzędzi.
  • 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 pomagali w przeglądach kodu i pomagali debugować wiele problemów z migracjami, które pojawiły się podczas aktualizowania samouczka dla 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 dla języka VB. Jeśli tworzysz 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ć/kopii w tle "DotNetOpenAuth.OpenId", gdy ten plik już istnieje.

Rozwiązanie 2.

Poczekaj kilka sekund i odśwież stronę.

Nie rozpoznano bazy danych Update-Database

Komunikat o błędzie:

Termin "Update-Database" nie jest rozpoznawany jako nazwa polecenia cmdlet, funkcji, pliku skryptu lub programu do obsługi. 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 2.

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 2.

Jedną z przyczyn tego problemu są błędy walidacji po uruchomieniu Seed metody. Aby uzyskać porady dotyczące debugowania metody, zobacz Bazy danych programu Entity Framework (EF) dotyczące rozmieszczania i debugowania 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 strony są nieprawidłowe.

Rozwiązanie 2.

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. Zazwyczaj można rozwiązać ten problem, 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 programu 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 2.

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