Condividi tramite


Scenari avanzati di Entity Framework per un'applicazione Web MVC (10 di 10)

di Tom Dykstra

L'applicazione Web di esempio Contoso University illustra come creare ASP.NET applicazioni MVC 4 usando Entity Framework 5 Code First e Visual Studio 2012. Per informazioni sulla serie di esercitazioni, vedere la prima esercitazione della serie.

Nota

Se si verifica un problema che non è possibile risolvere, scaricare il capitolo completato e provare a riprodurre il problema. In genere è possibile trovare la soluzione al problema confrontando il codice con il codice completato. Per alcuni errori comuni e come risolverli, vedere Errori e soluzioni alternative.

Nell'esercitazione precedente sono stati implementati il repository e l'unità di modelli di lavoro. Questa esercitazione illustra gli argomenti seguenti:

  • Esecuzione di query SQL non elaborate.
  • Esecuzione di query senza rilevamento.
  • Esame delle query inviate al database.
  • Uso delle classi proxy.
  • Disabilitazione del rilevamento automatico delle modifiche.
  • Disabilitazione della convalida durante il salvataggio delle modifiche.
  • Errori e soluzione alternativa

Per la maggior parte di questi argomenti, si useranno le pagine già create. Per usare SQL non elaborato per eseguire aggiornamenti in blocco, si creerà una nuova pagina che aggiorna il numero di crediti di tutti i corsi nel database:

Screenshot che mostra la pagina iniziale Update Course Credits .Screenshot che mostra la pagina iniziale Update Course Credits. Il numero 2 viene immesso nel campo di testo.

Per usare una query senza rilevamento, aggiungere una nuova logica di convalida alla pagina Modifica reparto:

Screenshot che mostra la pagina Contoso University Department Edit con un messaggio di errore di amministratore duplicato.

Esecuzione di query SQL non elaborate

L'API Code First di Entity Framework include metodi che consentono di passare i comandi SQL direttamente al database. Sono disponibili le seguenti opzioni:

  • Usare il metodo DbSet.SqlQuery per le query che restituiscono tipi di entità. Gli oggetti restituiti devono essere del tipo previsto dall'oggetto DbSet e vengono rilevati automaticamente dal contesto del database, a meno che non si disattiva il rilevamento. Vedere la sezione seguente sul AsNoTracking metodo .
  • Usare il Database.SqlQuery metodo per le query che restituiscono tipi che non sono entità. I dati restituiti non vengono registrati dal contesto di database, anche se il metodo viene usato per recuperare i tipi di entità.
  • Usare Database.ExecuteSqlCommand per i comandi non di query.

Uno dei vantaggi dell'utilizzo di Entity Framework è la mancanza di un collegamento troppo stretto del codice a un particolare metodo di archiviazione dei dati. Le query e i comandi SQL vengono generati automaticamente e non è necessario scriverli. Esistono tuttavia scenari eccezionali quando è necessario eseguire query SQL specifiche create manualmente e questi metodi consentono di gestire tali eccezioni.

Come avviene quando si eseguono comandi SQL in un'applicazione Web, è necessario adottare delle precauzioni per proteggere il sito dagli attacchi SQL injection. A questo scopo è possibile usare query parametrizzate per assicurarsi che le stringhe inviate da una pagina Web non possano essere interpretate come comandi SQL. In questa esercitazione verranno usate query parametrizzate quando l'input dell'utente viene integrato in una query.

Chiamata di una query che restituisce entità

Si supponga di voler consentire alla GenericRepository classe di offrire ulteriore flessibilità di filtro e ordinamento senza richiedere la creazione di una classe derivata con metodi aggiuntivi. Un modo per ottenere questo risultato consiste nell'aggiungere un metodo che accetta una query SQL. È quindi possibile specificare qualsiasi tipo di filtro o ordinamento desiderato nel controller, ad esempio una Where clausola che dipende da un join o da una sottoquery. In questa sezione verrà illustrato come implementare un metodo di questo tipo.

Creare il GetWithRawSql metodo aggiungendo il codice seguente a GenericRepository.cs:

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

In CourseController.cs chiamare il nuovo metodo dal Details metodo , come illustrato nell'esempio seguente:

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

In questo caso è possibile usare il GetByID metodo , ma si usa il GetWithRawSql metodo per verificare che il GetWithRawSQL metodo funzioni.

Eseguire la pagina Dettagli per verificare che la query di selezione funzioni (selezionare la scheda Corso e quindi Dettagli per un corso).

Screenshot che mostra la pagina Dettagli di Contoso University.

Chiamata di una query che restituisce altri tipi di oggetti

In precedenza è stata creata una griglia delle statistiche degli studenti per la pagina About che visualizza il numero di studenti per ogni data di registrazione. Il codice che esegue questa operazione in HomeController.cs usa LINQ:

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

Si supponga di voler scrivere il codice che recupera questi dati direttamente in SQL anziché usare LINQ. A tale scopo, è necessario eseguire una query che restituisce un valore diverso dagli oggetti entità, il che significa che è necessario usare il Database.SqlQuery metodo .

In HomeController.cs sostituire l'istruzione LINQ nel About metodo con il codice seguente:

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

Eseguire la pagina Informazioni su. Vengono visualizzati gli stessi dati visualizzati in precedenza.

Screenshot che mostra la pagina Informazioni su Contoso University.

Chiamata di una query di aggiornamento

Si supponga che gli amministratori di Contoso University vogliano essere in grado di eseguire modifiche in blocco nel database, ad esempio la modifica del numero di crediti per ogni corso. Se il numero di corsi dell'università è elevato, potrebbe non essere utile recuperarli tutti come entità e modificarli singolarmente. In questa sezione si implementerà una pagina Web che consente all'utente di specificare un fattore in base al quale modificare il numero di crediti per tutti i corsi e apportare la modifica eseguendo un'istruzione SQL UPDATE . La pagina Web apparirà come segue:

Screenshot che mostra la pagina iniziale Update Course Credits .Screenshot che mostra la pagina iniziale Update Course Credits. Il numero 2 viene immesso nel campo di testo.

Nell'esercitazione precedente è stato usato il repository generico per leggere e aggiornare Course le entità nel Course controller. Per questa operazione di aggiornamento in blocco, è necessario creare un nuovo metodo di repository che non si trova nel repository generico. A tale scopo, si creerà una classe dedicata CourseRepository che deriva dalla GenericRepository classe .

Nella cartella DAL creare CourseRepository.cs e sostituire il codice esistente con il codice seguente:

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);
        }

    }
}

In UnitOfWork.cs modificare il Course tipo di repository da GenericRepository<Course>aCourseRepository:

private CourseRepository courseRepository;
public CourseRepository CourseRepository
{
    get
    {

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

In CourseController.cs aggiungere un UpdateCourseCredits metodo:

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

Questo metodo verrà usato sia per che HttpPostper HttpGet . Quando viene eseguito il HttpGet UpdateCourseCredits metodo, la multiplier variabile sarà Null e la visualizzazione visualizzerà una casella di testo vuota e un pulsante di invio, come illustrato nella figura precedente.

Quando si fa clic sul pulsante Aggiorna e il HttpPost metodo viene eseguito, multiplier il valore immesso nella casella di testo verrà immesso. Il codice chiama quindi il metodo del repository UpdateCourseCredits , che restituisce il numero di righe interessate e tale valore viene archiviato nell'oggetto ViewBag . Quando la visualizzazione riceve il numero di righe interessate nell'oggetto ViewBag , visualizza tale numero anziché la casella di testo e il pulsante invia, come illustrato nella figura seguente:

Screenshot che mostra la pagina interessata dalle righe Crediti corso di aggiornamento contoso University.

Creare una visualizzazione nella cartella Views\Course per la pagina Update Course Credits :Create a view in the Views\Course folder for the Update Course Credits page:

Screenshot che mostra la finestra di dialogo Aggiungi visualizzazione. Aggiornare i crediti corsi viene immesso nel campo Visualizza nome testo.

In Views\Course\UpdateCourseCredits.cshtml sostituire il codice del modello con il codice seguente:

@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>

Eseguire il metodo UpdateCourseCredits selezionando la scheda Courses, quindi aggiungendo "/UpdateCourseCredits" alla fine dell'URL nella barra degli indirizzi del browser (ad esempio: http://localhost:50205/Course/UpdateCourseCredits). Immettere un numero nella casella di testo:

Screenshot che mostra la pagina iniziale Update Course Credits con il numero 2 immesso nel campo di testo.

Fai clic su Aggiorna. Viene visualizzato il numero di righe interessate:

Screenshot che mostra la pagina Update Course Credits con il numero di righe aggiornate.

Fare clic su Torna all'elenco per visualizzare l'elenco dei corsi con il numero di crediti modificato.

Screenshot che mostra la pagina Indice corsi. Viene visualizzato un elenco di corsi con il numero di crediti modificato.

Per altre informazioni sulle query SQL non elaborate, vedere Query SQL non elaborate nel blog del team di Entity Framework.

senza rilevamento delle modifiche

Quando un contesto di database recupera le righe di database e crea oggetti entità che li rappresentano, per impostazione predefinita tiene traccia del fatto che le entità in memoria siano sincronizzate con ciò che si trova nel database. I dati in memoria svolgono la funzione di una cache e vengono usati per l'aggiornamento di un'entità. Questa memorizzazione nella cache spesso non è necessaria in un'applicazione Web poiché le istanze del contesto hanno spesso una durata breve (viene creata ed eliminata una nuova istanza per ogni richiesta) e il contesto che legge un'entità viene in genere eliminato prima che l'entità venga riutilizzata.

È possibile specificare se il contesto tiene traccia degli oggetti entità per una query usando il AsNoTracking metodo . Gli scenari tipici in cui viene disabilitata la registrazione includono i seguenti:

  • La query recupera un volume di dati di questo tipo che disattiva il rilevamento potrebbe migliorare notevolmente le prestazioni.
  • Si vuole collegare un'entità per aggiornarla, ma in precedenza è stata recuperata la stessa entità per uno scopo diverso. Poiché l'entità viene già registrata dal contesto di database, non è possibile collegare l'entità che si vuole modificare. Un modo per evitare questo problema consiste nell'usare l'opzione AsNoTracking con la query precedente.

In questa sezione si implementerà la logica di business che illustra il secondo di questi scenari. In particolare, verrà applicata una regola business che indica che un insegnante non può essere l'amministratore di più di un reparto.

In DepartmentController.cs aggiungere un nuovo metodo che è possibile chiamare dai Edit metodi e Create per assicurarsi che nessun reparto abbia lo stesso amministratore:

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);
        }
    }
}

Aggiungere codice nel try blocco del HttpPost Edit metodo per chiamare questo nuovo metodo se non sono presenti errori di convalida. Il try blocco è ora simile all'esempio seguente:

[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;

Eseguire la pagina Modifica reparto e provare a modificare l'amministratore di un reparto in un insegnante che è già l'amministratore di un reparto diverso. Viene visualizzato il messaggio di errore previsto:

Screenshot che mostra la pagina Di modifica reparto con un messaggio di errore di amministratore duplicato.

Eseguire di nuovo la pagina Modifica reparto e questa volta modificare l'importo budget . Quando si fa clic su Salva, viene visualizzata una pagina di errore:

Screenshot che mostra la pagina Di modifica reparto con un messaggio di errore di Gestione stato oggetto.

Il messaggio di errore di eccezione è "An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key." Si è verificato a causa della sequenza di eventi seguente:

  • Il Edit metodo chiama il ValidateOneAdministratorAssignmentPerInstructor metodo , che recupera tutti i reparti che hanno Kim Abercrombie come amministratore. Ciò fa sì che il reparto inglese venga letto. Poiché si tratta del reparto da modificare, non viene segnalato alcun errore. In seguito a questa operazione di lettura, tuttavia, l'entità del reparto inglese letta dal database viene ora rilevata dal contesto del database.
  • Il Edit metodo tenta di impostare il Modified flag sull'entità del reparto inglese creata dal gestore di associazione di modelli MVC, ma l'operazione ha esito negativo perché il contesto tiene già traccia di un'entità per il reparto inglese.

Una soluzione a questo problema consiste nel impedire al contesto di tenere traccia delle entità del reparto in memoria recuperate dalla query di convalida. Non c'è alcun svantaggio per farlo, perché non si aggiornerà questa entità o la si leggerà di nuovo in modo da trarre vantaggio dalla memorizzazione nella cache in memoria.

In DepartmentController.cs, nel ValidateOneAdministratorAssignmentPerInstructor metodo specificare nessun rilevamento, come illustrato di seguito:

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

Ripetere il tentativo di modificare l'importo budget di un reparto. Questa volta che l'operazione ha esito positivo e il sito viene restituito come previsto nella pagina Indice reparti, che mostra il valore del budget modificato.

Esame delle query inviate al database

A volte può essere utile visualizzare le query SQL inviate al database. A tale scopo, è possibile esaminare una variabile di query nel debugger o chiamare il metodo della ToString query. Per provare questa operazione, si esaminerà una query semplice e quindi si esaminerà cosa accade quando si aggiungono opzioni come caricamento eager, filtro e ordinamento.

In Controllers/CourseController sostituire il Index metodo con il codice seguente:

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

Impostare ora un punto di interruzione in GenericRepository.cs sulle return query.ToList(); istruzioni e return orderBy(query).ToList(); del Get metodo . Eseguire il progetto in modalità di debug e selezionare la pagina Indice corso. Quando il codice raggiunge il punto di interruzione, esaminare la query variabile. Viene visualizzata la query inviata a SQL Server. È una semplice Select affermazione:

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

Screenshot che mostra la scheda Repository generico dell'applicazione Web di esempio. La variabile di query è selezionata.

Le query possono essere troppo lunghe da visualizzare nelle finestre di debug in Visual Studio. Per visualizzare l'intera query, è possibile copiare il valore della variabile e incollarlo in un editor di testo:

Screenshot che mostra il valore della variabile con un menu a discesa visualizzato quando è selezionato. L'opzione Copia valore è evidenziata.

A questo punto si aggiungerà un elenco a discesa alla pagina Indice corso in modo che gli utenti possano filtrare per un determinato reparto. I corsi verranno ordinati in base al titolo e si specificherà il caricamento eager per la Department proprietà di navigazione. In CourseController.cs sostituire il Index metodo con il codice seguente:

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"));
}

Il metodo riceve il valore selezionato dell'elenco a discesa nel SelectedDepartment parametro . Se non è selezionata alcuna opzione, questo parametro sarà Null.

Una SelectList raccolta contenente tutti i reparti viene passata alla visualizzazione per l'elenco a discesa. I parametri passati al SelectList costruttore specificano il nome del campo valore, il nome del campo di testo e l'elemento selezionato.

Per il Get metodo del Course repository, il codice specifica un'espressione di filtro, un ordinamento e il caricamento eager per la proprietà di Department navigazione. L'espressione di filtro restituisce true sempre se nell'elenco a discesa non è selezionato nulla, SelectedDepartment ovvero null.

In Views\Course\Index.cshtml, immediatamente prima del tag di apertura table , aggiungere il codice seguente per creare l'elenco a discesa e un pulsante di invio:

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

Con i punti di interruzione ancora impostati nella GenericRepository classe , eseguire la pagina Indice corso. Continuare con le prime due volte in cui il codice raggiunge un punto di interruzione, in modo che la pagina venga visualizzata nel browser. Selezionare un reparto dall'elenco a discesa e fare clic su Filtro:

Screenshot che mostra la pagina Indice corso con l'opzione Reparto economia selezionata.

Questa volta il primo punto di interruzione sarà per la query dei reparti per l'elenco a discesa. Ignorare questa variabile e visualizzare la query variabile al successivo raggiungimento del punto di interruzione per visualizzare l'aspetto della Course query. Verrà visualizzato un aspetto simile al seguente:

{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)}

È possibile notare che la query è ora una JOIN query che carica Department i dati insieme ai Course dati e che include una WHERE clausola .

Uso delle classi proxy

Quando Entity Framework crea istanze di entità, ad esempio quando si esegue una query, spesso le crea come istanze di un tipo derivato generato dinamicamente che funge da proxy per l'entità. Questo proxy esegue l'override di alcune proprietà virtuali dell'entità per inserire hook per l'esecuzione automatica di azioni quando si accede alla proprietà. Ad esempio, questo meccanismo viene usato per supportare il caricamento differita delle relazioni.

Nella maggior parte dei casi non è necessario conoscere questo uso di proxy, ma esistono eccezioni:

  • In alcuni scenari potrebbe essere necessario impedire a Entity Framework di creare istanze proxy. Ad esempio, la serializzazione di istanze non proxy potrebbe essere più efficiente rispetto alla serializzazione delle istanze proxy.
  • Quando si crea un'istanza di una classe di entità usando l'operatore , non si ottiene un'istanza new del proxy. Ciò significa che non si ottengono funzionalità come il caricamento differita e il rilevamento automatico delle modifiche. Questo è in genere ok; in genere non è necessario eseguire il caricamento differita, perché si sta creando una nuova entità che non si trova nel database e in genere non è necessario eseguire il rilevamento delle modifiche se si contrassegna in modo esplicito l'entità come Added. Tuttavia, se è necessario il caricamento differita ed è necessario il rilevamento delle modifiche, è possibile creare nuove istanze di entità con proxy usando il Create metodo della DbSet classe .
  • Potrebbe essere necessario ottenere un tipo di entità effettivo da un tipo proxy. È possibile usare il GetObjectType metodo della ObjectContext classe per ottenere il tipo di entità effettivo di un'istanza del tipo proxy.

Per altre informazioni, vedere Uso dei proxy nel blog del team di Entity Framework.

Disabilitazione del rilevamento automatico delle modifiche

Entity Framework determina come è stata modificata un'entità (e di conseguenza gli aggiornamenti da inviare al database) confrontando i valori correnti di un'entità con i valori originali. I valori originali vengono archiviati quando l'entità è stata sottoposta a query o associata. I metodi che causano il rilevamento automatico delle modifiche includono:

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

Se si rileva un numero elevato di entità e si chiama uno di questi metodi più volte in un ciclo, è possibile ottenere miglioramenti significativi delle prestazioni disattivando temporaneamente il rilevamento automatico delle modifiche usando la proprietà AutoDetectChangesEnabled . Per altre informazioni, vedere Rilevamento automatico delle modifiche.

Disabilitazione della convalida durante il salvataggio delle modifiche

Quando si chiama il SaveChanges metodo, per impostazione predefinita Entity Framework convalida i dati in tutte le proprietà di tutte le entità modificate prima di aggiornare il database. Se è stato aggiornato un numero elevato di entità e i dati sono già stati convalidati, questo lavoro non è necessario ed è possibile che il processo di salvataggio delle modifiche richiede meno tempo disattivando temporaneamente la convalida. A tale scopo, è possibile usare la proprietà ValidateOnSaveEnabled . Per ulteriori informazioni, consultare Convalida.

Riepilogo

Questa serie di esercitazioni sull'uso di Entity Framework in un'applicazione MVC ASP.NET completa questa serie di esercitazioni. I collegamenti ad altre risorse di Entity Framework sono disponibili nella mappa del contenuto di accesso ai dati ASP.NET.

Per altre informazioni su come distribuire l'applicazione Web dopo averlo compilato, vedere ASP.NET Deployment Content Map in MSDN Library.

Per informazioni su altri argomenti correlati a MVC, ad esempio l'autenticazione e l'autorizzazione, vedere Le risorse consigliate per MVC.

Riconoscimenti

  • Tom Dykstra ha scritto la versione originale di questa esercitazione ed è un senior programming writer del team di contenuto Piattaforma Web Microsoft e tools.
  • Rick Anderson (twitter @RickAndMSFT) ha creato questa esercitazione e ha eseguito la maggior parte del lavoro aggiornandolo per EF 5 e MVC 4. Rick è un senior programming writer per Microsoft incentrato su Azure e MVC.
  • Rowan Miller e altri membri del team di Entity Framework hanno assistito con revisioni del codice e hanno contribuito a eseguire il debug di molti problemi con le migrazioni che si sono verificati durante l'aggiornamento dell'esercitazione per EF 5.

VB

Quando l'esercitazione è stata originariamente prodotta, sono state fornite versioni C# e VB del progetto di download completato. Con questo aggiornamento viene fornito un progetto scaricabile C# per ogni capitolo per semplificare l'avvio ovunque nella serie, ma a causa di limitazioni temporali e altre priorità non è stato fatto per VB. Se si compila un progetto VB usando queste esercitazioni e si è disposti a condividerlo con altri utenti, segnalarlo.

Errori e soluzioni alternative

Impossibile creare/copiare shadow

Messaggio di errore:

Impossibile creare/shadow copy 'DotNetOpenAuth.OpenId' quando il file esiste già.

Soluzione:

Attendere alcuni secondi e aggiornare la pagina.

Update-Database non riconosciuto

Messaggio di errore:

Il termine 'Update-Database' non viene riconosciuto come nome di un cmdlet, di una funzione, di un file di script o di un programma eseguibile. Verificare l'ortografia del nome, che il percorso sia incluso e corretto, quindi riprovare.Dal Update-Database comando in PMC.

Soluzione:

Uscire da Visual Studio. Riaprire il progetto e riprovare.

Convalida non riuscita

Messaggio di errore:

Convalida non riuscita per una o più entità. Per altri dettagli, vedere la proprietà 'EntityValidationErrors'. Dal Update-Database comando in PMC.

Soluzione:

Una causa di questo problema è costituita dagli errori di convalida durante l'esecuzione del Seed metodo. Vedere Seeding and Debugging Entity Framework (EF) DBs (Seeding and Debugging Entity Framework) (Seeding and Debugging Entity Framework (EF) DBs (Seeding and Debugging Entity Framework) (Seeding and Debugging Entity Framework (EF) DBs ( Seed Seeding and Debugging Entity Framework

Errore HTTP 500.19

Messaggio di errore:

Errore HTTP 500.19 - Errore interno del server
Impossibile accedere alla pagina richiesta perché i dati di configurazione correlati per la pagina non sono validi.

Soluzione:

Un modo per ottenere questo errore consiste nell'avere più copie della soluzione, ognuna usando lo stesso numero di porta. In genere è possibile risolvere questo problema chiudendo tutte le istanze di Visual Studio, quindi riavviando il progetto su cui si lavora. In caso contrario, provare a modificare il numero di porta. Fare clic con il pulsante destro del mouse sul file di progetto e quindi scegliere proprietà. Selezionare la scheda Web e quindi modificare il numero di porta nella casella di testo Url progetto.

Errore di individuazione dell'istanza di SQL Server

Messaggio di errore:

Si è verificato un errore di rete o specifico dell'istanza mentre veniva stabilita la connessione a SQL Server. Il server non è stato trovato o non è accessibile. Verificare che il nome dell'istanza sia corretto e che il server sia configurato in modo da consentire connessioni remote. (provider: interfacce di rete SQL, errore: 26 - Errore nell'individuazione del server/dell'istanza specificata)

Soluzione:

Controllare stringa di connessione. Se il database è stato eliminato manualmente, modificare il nome del database nella stringa di costruzione.