Share via


Aggiunta di un nuovo campo

di Rick Anderson

Nota

Una versione aggiornata di questa esercitazione è disponibile qui usando la versione più recente di Visual Studio. La nuova esercitazione usa ASP.NET Core MVC, che offre molti miglioramenti in questa esercitazione.

Questa esercitazione illustra ASP.NET Core MVC con i controller e le viste. Razor Pages è una nuova alternativa in ASP.NET Core, un modello di programmazione basato su pagine che semplifica e rende più produttiva la creazione dell'interfaccia utente Web. È consigliabile provare l'esercitazione sulle pagine Razor prima della versione MVC. L'esercitazione sulle pagine Razor:

  • È più semplice da seguire.
  • Riguarda più funzionalità.
  • È l'approccio preferito per lo sviluppo di nuove app.

In questa sezione si useranno Migrazioni Code First di Entity Framework per eseguire la migrazione di alcune modifiche alle classi del modello in modo che la modifica venga applicata al database.

Per impostazione predefinita, quando si usa Entity Framework Code First per creare automaticamente un database, come illustrato in precedenza in questa esercitazione, Code First aggiunge una tabella al database per tenere traccia se lo schema del database è sincronizzato con le classi di modello da cui è stato generato. Se non sono sincronizzati, Entity Framework genera un errore. In questo modo è più semplice tenere traccia dei problemi in fase di sviluppo che potrebbero essere rilevati solo (da errori oscurati) in fase di esecuzione.

Configurazione di Migrazioni Code First per le modifiche del modello

Passare a Esplora soluzioni. Fare clic con il pulsante destro del mouse sul file Movies.mdf e scegliere Elimina per rimuovere il database movies. Se il file Movies.mdf non viene visualizzato, fare clic sull'icona Mostra tutti i file mostrata di seguito nella struttura rossa.

Screenshot che mostra la scheda Movies Controller dot c s e Esplora soluzioni aperta. L'icona Mostra tutti i file è in rosso.

Compilare l'applicazione e verificare che non siano presenti errori.

Scegliere Gestione pacchetti NuGet dal menu Strumenti e quindi Console di Gestione pacchetti.

Aggiungi pack man

Nella finestra Console di Gestione pacchetti immettere al PM> prompt

Enable-Migrations -ContextTypeName MvcMovie.Models.MovieDBContext

Screenshot che mostra la finestra Console di Gestione pacchetti. Il testo nel comando Abilita migrazioni è evidenziato.

Il comando Enable-Migrations (illustrato sopra) crea un file Configuration.cs in una nuova cartella Migrations .

Screenshot che mostra il Esplora soluzioni. La sottocartella Configuration dot c s della cartella Migrations è selezionata.

Visual Studio apre il file Configuration.cs . Sostituire il Seed metodo nel file Configuration.cs con il codice seguente:

protected override void Seed(MvcMovie.Models.MovieDBContext context)
{
    context.Movies.AddOrUpdate( i => i.Title,
        new Movie
        {
            Title = "When Harry Met Sally",
            ReleaseDate = DateTime.Parse("1989-1-11"),
            Genre = "Romantic Comedy",
            Price = 7.99M
        },

         new Movie
         {
             Title = "Ghostbusters ",
             ReleaseDate = DateTime.Parse("1984-3-13"),
             Genre = "Comedy",
             Price = 8.99M
         },

         new Movie
         {
             Title = "Ghostbusters 2",
             ReleaseDate = DateTime.Parse("1986-2-23"),
             Genre = "Comedy",
             Price = 9.99M
         },

       new Movie
       {
           Title = "Rio Bravo",
           ReleaseDate = DateTime.Parse("1959-4-15"),
           Genre = "Western",
           Price = 3.99M
       }
   );
   
}

Passare il puntatore del mouse sulla linea ondulata rossa sotto Movie e fare clic e quindi fare clic Show Potential Fixessu usandoMvcMovie.Models;

Screenshot che mostra il menu Mostra correzioni potenziali. Viene selezionato M V C Movie Dot Models e viene visualizzato un avviso non trovato.

In questo modo viene aggiunta l'istruzione using seguente:

using MvcMovie.Models;

Nota

Migrazioni Code First chiama il Seed metodo dopo ogni migrazione, ovvero la chiamata a update-database nella console di Gestione pacchetti, e questo metodo aggiorna le righe già inserite o le inserisce se non esistono ancora.

Il metodo AddOrUpdate nel codice seguente esegue un'operazione "upsert":

context.Movies.AddOrUpdate(i => i.Title,
    new Movie
    {
        Title = "When Harry Met Sally",
        ReleaseDate = DateTime.Parse("1989-1-11"),
        Genre = "Romantic Comedy",
        Rating = "PG",
        Price = 7.99M
    }

Poiché il metodo Seed viene eseguito con ogni migrazione, non è possibile inserire solo i dati, perché le righe che si sta tentando di aggiungere saranno già presenti dopo la prima migrazione che crea il database. L'operazione "upsert" impedisce errori che si verificherebbero se si tenta di inserire una riga già esistente, ma esegue l'override delle modifiche ai dati che potrebbero essere state apportate durante il test dell'applicazione. Con i dati di test in alcune tabelle potrebbe non essere necessario eseguire questa operazione: in alcuni casi quando si modificano i dati durante il test si vuole che le modifiche rimangano dopo gli aggiornamenti del database. In tal caso si vuole eseguire un'operazione di inserimento condizionale: inserire una riga solo se non esiste già.

Il primo parametro passato al metodo AddOrUpdate specifica la proprietà da utilizzare per verificare se esiste già una riga. Per i dati dei film di test forniti, la Title proprietà può essere usata a questo scopo perché ogni titolo nell'elenco è univoco:

context.Movies.AddOrUpdate(i => i.Title,

Questo codice presuppone che i titoli siano univoci. Se si aggiunge manualmente un titolo duplicato, si otterrà l'eccezione seguente alla successiva esecuzione di una migrazione.

Sequenza contiene più di un elemento

Per altre informazioni sul metodo AddOrUpdate , vedere Prestare attenzione al metodo AddOrUpdate di EF 4.3.

Premere CTRL+MAIUSC-B per compilare il progetto.Se non si compila a questo punto, la procedura seguente avrà esito negativo.

Il passaggio successivo consiste nel creare una DbMigration classe per la migrazione iniziale. Questa migrazione crea un nuovo database, motivo per cui è stato eliminato il file movie.mdf in un passaggio precedente.

Nella finestra Console di Gestione pacchetti immettere il comando add-migration Initial per creare la migrazione iniziale. Il nome "Initial" è arbitrario e viene usato per denominare il file di migrazione creato.

Screenshot che mostra la console di Gestione pacchetti. Il testo nel comando aggiungi migrazione è evidenziato.

Migrazioni Code First crea un altro file di classe nella cartella Migrations (con il nome {DateStamp}_Initial.cs) e questa classe contiene il codice che crea lo schema del database. Il nome file di migrazione è pre-corretto con un timestamp per facilitare l'ordinamento. Esaminare il file {DateStamp}_Initial.cs , che contiene le istruzioni per creare la Movies tabella per Movie DB. Quando si aggiorna il database nelle istruzioni seguenti, questo file {DateStamp}_Initial.cs verrà eseguito e creato lo schema del database. Il metodo Seed verrà quindi eseguito per popolare il database con i dati di test.

Nella console di Gestione pacchetti immettere il comando update-database per creare il database ed eseguire il Seed metodo .

Screenshot che mostra la console di Gestione pacchetti. Il comando update database si trova nella finestra.

Se viene visualizzato un errore che indica che esiste già una tabella e non è possibile crearla, è probabile che l'applicazione sia stata eseguita dopo l'eliminazione del database e prima dell'esecuzione update-databasedi . In tal caso, eliminare nuovamente il file Movies.mdf e ripetere il update-database comando. Se si verifica ancora un errore, eliminare la cartella e il contenuto delle migrazioni, quindi iniziare con le istruzioni nella parte superiore di questa pagina (ovvero eliminare il file Movies.mdf e quindi procedere a Enable-Migrations). Se viene comunque visualizzato un errore, aprire SQL Server Esplora oggetti e rimuovere il database dall'elenco. Se viene visualizzato un errore che indica che "Impossibile collegare il file con estensione mdf come database", rimuovere la proprietà Initial Catalog come parte della stringa di connessione nel file web.config .

Eseguire l'applicazione e passare all'URL /Movies . Vengono visualizzati i dati di inizializzazione.

Screenshot che mostra l'indice dei film M V C con quattro film elencati.

Aggiunta di una proprietà Rating al modello Movie

Per iniziare, aggiungere una nuova Rating proprietà alla classe esistente Movie . Aprire il file Models\Movie.cs e aggiungere la Rating proprietà come segue:

public string Rating { get; set; }

La classe completa Movie è ora simile al codice seguente:

public class Movie
{
    public int ID { get; set; }
    public string Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
    public DateTime ReleaseDate { get; set; }
    public string Genre { get; set; }
    public decimal Price { get; set; }
    public string Rating { get; set; }
}

Compilare l'applicazione (CTRL+MAIUSC+B).

Poiché è stato aggiunto un nuovo campo alla Movie classe, è anche necessario aggiornare l'elenco di elementi consentiti di associazione in modo che questa nuova proprietà venga inclusa. Aggiornare l'attributo bind per Create i metodi di azione e Edit per includere la Rating proprietà :

[Bind(Include = "ID,Title,ReleaseDate,Genre,Price,Rating")]

È necessario anche aggiornare i modelli di vista per visualizzare, creare e modificare la nuova proprietà Rating nella vista del browser.

Aprire il file \Views\Movies\Index.cshtml e aggiungere un'intestazione di <th>Rating</th> colonna subito dopo la colonna Price . Aggiungere quindi una <td> colonna alla fine del modello per eseguire il rendering del @item.Rating valore. Di seguito è riportato l'aspetto del modello di visualizzazione Index.cshtml aggiornato:

@model IEnumerable<MvcMovie.Models.Movie>
@{
    ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
    @Html.ActionLink("Create New", "Create")
    @using (Html.BeginForm("Index", "Movies", FormMethod.Get))
    {
    <p>
        Genre: @Html.DropDownList("movieGenre", "All")
        Title: @Html.TextBox("SearchString")
        <input type="submit" value="Filter" />
    </p>
    }
</p>
<table class="table">
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Title)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.ReleaseDate)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Genre)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Price)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Rating)
        </th>

        <th></th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Title)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.ReleaseDate)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Genre)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Price)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Rating)
        </td>

        <td>
            @Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
            @Html.ActionLink("Details", "Details", new { id=item.ID }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.ID })
        </td>
    </tr>
}

</table>

Aprire quindi il file \Views\Movies\Create.cshtml e aggiungere il Rating campo con il markup evidenziato seguente. Viene eseguito il rendering di una casella di testo in modo che sia possibile specificare una classificazione quando viene creato un nuovo filmato.

<div class="form-group">
            @Html.LabelFor(model => model.Price, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Price, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Price, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Rating, new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Rating, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Rating, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

Il codice dell'applicazione è stato aggiornato per supportare la nuova Rating proprietà.

Eseguire l'applicazione e passare all'URL /Movies . Quando si esegue questa operazione, tuttavia, verrà visualizzato uno degli errori seguenti:

Screenshot che mostra un errore eccezione non gestito dall'utente.

Il modello che esegue il backup del contesto 'MovieDBContext' è stato modificato dopo la creazione del database. Consider using Code First Migrations to update the database (https://go.microsoft.com/fwlink/?LinkId=238269) (Il modello di creazione del contesto 'BlogContext' è stato modificato dopo la creazione del database. È possibile usare Migrazioni Code First per aggiornare il database).

Screenshot che mostra un browser con l'errore del server di notifica nell'applicazione.

Questo errore viene visualizzato perché la classe del modello aggiornata Movie nell'applicazione è ora diversa dallo schema della Movie tabella del database esistente. Nella tabella del database non è presente una colonna Rating.

Per correggere questo errore, esistono alcuni approcci:

  1. Fare in modo che Entity Framework elimini e crei di nuovo automaticamente il database in base al nuovo schema di classi del modello. Questo approccio è molto utile nelle prime fasi del ciclo di sviluppo in una fase attiva di sviluppo di un database di test e consente di migliorare rapidamente lo schema del modello e il database insieme. Lo svantaggio, tuttavia, è che si perdono i dati esistenti nel database, quindi non si vuole usare questo approccio in un database di produzione. Un modo efficace per sviluppare un'applicazione consiste nell'inizializzare automaticamente un database con dati di test usando un inizializzatore. Per altre informazioni sugli inizializzatori di database di Entity Framework, vedere ASP.NET esercitazione su MVC/Entity Framework.
  2. Modificare esplicitamente lo schema del database esistente in modo che corrisponda alle classi del modello. Il vantaggio di questo approccio è che i dati vengono mantenuti. È possibile apportare questa modifica manualmente o creando uno script di modifica del database.
  3. Usare Migrazioni Code First per aggiornare lo schema del database.

Per questa esercitazione si userà Migrazioni Code First.

Aggiornare il metodo Seed in modo che fornisca un valore per la nuova colonna. Aprire il file Migrations\Configuration.cs e aggiungere un campo Rating a ogni oggetto Movie.

new Movie
{
    Title = "When Harry Met Sally",
    ReleaseDate = DateTime.Parse("1989-1-11"),
    Genre = "Romantic Comedy",
    Rating = "PG",
    Price = 7.99M
},

Compilare la soluzione e quindi aprire la finestra Console di Gestione pacchetti e immettere il comando seguente:

add-migration Rating

Il add-migration comando indica al framework di migrazione di esaminare il modello di film corrente con lo schema del database movie corrente e creare il codice necessario per eseguire la migrazione del database al nuovo modello. Il nome Rating è arbitrario e viene usato per denominare il file di migrazione. È utile usare un nome significativo per il passaggio di migrazione.

Al termine di questo comando, Visual Studio apre il file di classe che definisce la nuova DbMigration classe derivata e nel Up metodo è possibile visualizzare il codice che crea la nuova colonna.

public partial class AddRatingMig : DbMigration
{
    public override void Up()
    {
        AddColumn("dbo.Movies", "Rating", c => c.String());
    }
    
    public override void Down()
    {
        DropColumn("dbo.Movies", "Rating");
    }
}

Compilare la soluzione e quindi immettere il update-database comando nella finestra Console di Gestione pacchetti .

L'immagine seguente mostra l'output nella finestra Console di Gestione pacchetti (Il timbro di data in sospeso Rating sarà diverso).

Screenshot che mostra la finestra Console di Gestione pacchetti con il comando update database immesso.

Eseguire di nuovo l'applicazione e passare all'URL /Movies. È possibile visualizzare il nuovo campo Valutazione.

Screenshot che mostra l'elenco M V C Movie Index con il campo Rating aggiunto.

Fare clic sul collegamento Crea nuovo per aggiungere un nuovo filmato. Si noti che è possibile aggiungere una classificazione.

7_CreateRioII

Fare clic su Crea. Il nuovo film, incluso il rating, ora viene visualizzato nell'elenco dei film:

7_ourNewMovie_SM

Ora che il progetto usa le migrazioni, non sarà necessario eliminare il database quando si aggiunge un nuovo campo o si aggiorna in altro modo lo schema. Nella sezione successiva verranno apportate altre modifiche allo schema e verranno usate le migrazioni per aggiornare il database.

È anche necessario aggiungere il Rating campo ai modelli di visualizzazione Modifica, Dettagli ed Elimina.

È possibile immettere di nuovo il comando "update-database" nella finestra della console di Gestione pacchetti e non verrà eseguito alcun codice di migrazione, perché lo schema corrisponde al modello. Tuttavia, l'esecuzione di "update-database" eseguirà di nuovo il Seed metodo e, se si modifica uno dei dati di inizializzazione, le modifiche andranno perse perché il metodo esegue l'upsert Seed dei dati. Per altre informazioni sul metodo, vedere l'esercitazione Seed più diffusa di Tom Dykstra ASP.NET MVC/Entity Framework.

In questa sezione è stato illustrato come modificare gli oggetti modello e mantenere il database sincronizzato con le modifiche. Si è anche appreso un modo per popolare un database appena creato con dati di esempio in modo da poter provare gli scenari. Questa è stata solo una rapida introduzione a Code First, vedere Creazione di un modello di dati di Entity Framework per un'applicazione MVC ASP.NET per un'esercitazione più completa sull'argomento. Si esamini ora come aggiungere logica di convalida più completa alle classi di modello e abilitare alcune regole business da applicare.