Condividi tramite


Esame dei metodi di azione e delle visualizzazioni per il controller di film

di Rick Anderson

Nota

Una versione aggiornata di questa esercitazione è disponibile qui che usa ASP.NET MVC 5 e Visual Studio 2013. È più sicuro, molto più semplice da seguire e dimostra più funzionalità.

In questa sezione verranno esaminati i metodi di azione generati e le visualizzazioni per il controller di film. Si aggiungerà quindi una pagina di ricerca personalizzata.

Eseguire l'applicazione e passare al Movies controller aggiungendo /Movies all'URL nella barra degli indirizzi del browser. Tenere premuto il puntatore del mouse su un collegamento Modifica per visualizzare l'URL a cui si collega.

EditLink_sm

Il collegamento Edit è stato generato dal Html.ActionLink metodo nella visualizzazione Views\Movies\Index.cshtml :

@Html.ActionLink("Edit", "Edit", new { id=item.ID })

Html.ActionLink

L'oggetto Html è un helper esposto usando una proprietà nella classe di base System.Web.Mvc.WebViewPage . Il ActionLink metodo dell'helper semplifica la generazione dinamica di collegamenti ipertestuali HTML che si collegano ai metodi di azione nei controller. Il primo argomento del metodo è il testo del collegamento di cui eseguire il ActionLink rendering, ad esempio <a>Edit Me</a>. Il secondo argomento è il nome del metodo di azione da richiamare. L'argomento finale è un oggetto anonimo che genera i dati di route (in questo caso l'ID di 4).

Il collegamento generato illustrato nell'immagine precedente è http://localhost:xxxxx/Movies/Edit/4. La route predefinita (stabilita in App_Start\RouteConfig.cs) accetta il modello di {controller}/{action}/{id}URL . Pertanto, ASP.NET si traduce http://localhost:xxxxx/Movies/Edit/4 in una richiesta al Edit metodo di azione del Movies controller con il parametro ID uguale a 4. Esaminare il codice seguente dal file App_Start\RouteConfig.cs .

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", 
            id = UrlParameter.Optional }
    );
}

È anche possibile passare parametri del metodo di azione usando una stringa di query. Ad esempio, l'URL http://localhost:xxxxx/Movies/Edit?ID=4 passa anche il parametro ID 4 al Edit metodo di azione del Movies controller.

EditQueryString

Aprire il Movies controller. I due Edit metodi di azione sono illustrati di seguito.

//
// GET: /Movies/Edit/5

public ActionResult Edit(int id = 0)
{
    Movie movie = db.Movies.Find(id);
    if (movie == null)
    {
        return HttpNotFound();
    }
    return View(movie);
}

//
// POST: /Movies/Edit/5

[HttpPost]
public ActionResult Edit(Movie movie)
{
    if (ModelState.IsValid)
    {
        db.Entry(movie).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(movie);
}

Si noti che il secondo metodo di azione Edit è preceduto dall'attributo HttpPost. Questo attributo specifica che l'overload del Edit metodo può essere richiamato solo per le richieste POST. È possibile applicare l'attributo HttpGet al primo metodo di modifica, ma non è necessario perché è l'impostazione predefinita. Si farà riferimento ai metodi di azione assegnati in modo implicito all'attributo HttpGet come HttpGet metodi.

Il HttpGetEdit metodo accetta il parametro DELL'ID filmato, cerca il filmato usando il metodo Entity Framework Find e restituisce il filmato selezionato alla visualizzazione Modifica. Il parametro ID specifica un valore predefinito pari a zero se il Edit metodo viene chiamato senza un parametro. Se non è possibile trovare un filmato, viene restituito HttpNotFound . Quando il sistema di scaffolding ha creato la vista Edit, ha esaminato la classe Movie e il codice creato per eseguire il rendering degli elementi <label> e <input> per ogni proprietà della classe. L'esempio seguente mostra la visualizzazione Modifica generata:

@model MvcMovie.Models.Movie

@{
    ViewBag.Title = "Edit";
}

<h2>Edit</h2>

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)

    <fieldset>
        <legend>Movie</legend>

        @Html.HiddenFor(model => model.ID)

        <div class="editor-label">
            @Html.LabelFor(model => model.Title)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Title)
            @Html.ValidationMessageFor(model => model.Title)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ReleaseDate)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ReleaseDate)
            @Html.ValidationMessageFor(model => model.ReleaseDate)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Genre)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Genre)
            @Html.ValidationMessageFor(model => model.Genre)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Price)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Price)
            @Html.ValidationMessageFor(model => model.Price)
        </div>

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

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

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

Si noti che il modello di visualizzazione ha un'istruzione @model MvcMovie.Models.Movie all'inizio del file. Ciò specifica che la visualizzazione prevede che il modello per il modello di visualizzazione sia di tipo Movie.

Il codice con scaffolding usa diversi metodi helper per semplificare il markup HTML. L'helper Html.LabelFor visualizza il nome del campo ("Title", "ReleaseDate", "Genre" o "Price"). L'helper esegue il Html.EditorFor rendering di un elemento HTML <input> . L'helper Html.ValidationMessageFor visualizza tutti i messaggi di convalida associati a tale proprietà.

Eseguire l'applicazione e passare all'URL /Movies . Fare clic su un collegamento Modifica . Nel browser visualizzare l'origine per la pagina. Il codice HTML per l'elemento del modulo è illustrato di seguito.

<form action="/Movies/Edit/4" method="post">    <fieldset>
        <legend>Movie</legend>

        <input data-val="true" data-val-number="The field ID must be a number." data-val-required="The ID field is required." id="ID" name="ID" type="hidden" value="4" />

        <div class="editor-label">
            <label for="Title">Title</label>
        </div>
        <div class="editor-field">
            <input class="text-box single-line" id="Title" name="Title" type="text" value="Rio Bravo" />
            <span class="field-validation-valid" data-valmsg-for="Title" data-valmsg-replace="true"></span>
        </div>

        <div class="editor-label">
            <label for="ReleaseDate">ReleaseDate</label>
        </div>
        <div class="editor-field">
            <input class="text-box single-line" data-val="true" data-val-date="The field ReleaseDate must be a date." data-val-required="The ReleaseDate field is required." id="ReleaseDate" name="ReleaseDate" type="text" value="4/15/1959 12:00:00 AM" />
            <span class="field-validation-valid" data-valmsg-for="ReleaseDate" data-valmsg-replace="true"></span>
        </div>

        <div class="editor-label">
            <label for="Genre">Genre</label>
        </div>
        <div class="editor-field">
            <input class="text-box single-line" id="Genre" name="Genre" type="text" value="Western" />
            <span class="field-validation-valid" data-valmsg-for="Genre" data-valmsg-replace="true"></span>
        </div>

        <div class="editor-label">
            <label for="Price">Price</label>
        </div>
        <div class="editor-field">
            <input class="text-box single-line" data-val="true" data-val-number="The field Price must be a number." data-val-required="The Price field is required." id="Price" name="Price" type="text" value="2.99" />
            <span class="field-validation-valid" data-valmsg-for="Price" data-valmsg-replace="true"></span>
        </div>

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
</form>

Gli <input> elementi si trovano in un elemento HTML <form> il cui action attributo è impostato per l'inserimento nell'URL /Movies/Edit . I dati del modulo verranno inseriti nel server quando si fa clic sul pulsante Modifica .

Elaborazione della richiesta POST

Nell'elenco seguente viene indicata la versione HttpPost del metodo di azione Edit.

[HttpPost] 
public ActionResult Edit(Movie movie)  
{ 
    if (ModelState.IsValid)  
    { 
        db.Entry(movie).State = EntityState.Modified; 
        db.SaveChanges(); 
        return RedirectToAction("Index"); 
    } 
    return View(movie); 
}

Lo strumento di associazione di modelli MVC ASP.NET accetta i valori del modulo inviati e crea un Movie oggetto passato come movie parametro. Il metodo ModelState.IsValid verifica che i dati inviati nel formato possano essere usati per cambiare (modificare o aggiornare) un oggetto Movie. Se i dati sono validi, i dati dei film vengono salvati nella Movies raccolta dell'istanza db(MovieDBContext di . I nuovi dati dei film vengono salvati nel database chiamando il SaveChanges metodo di MovieDBContext. Dopo aver salvato i dati, il codice reindirizza l'utente al Index metodo di azione della MoviesController classe , che visualizza l'oggetto della raccolta di film, incluse le modifiche appena apportate.

Se i valori inseriti non sono validi, vengono rieseguiti nel modulo. Gli Html.ValidationMessageFor helper nel modello di visualizzazione Edit.cshtml si occupano della visualizzazione dei messaggi di errore appropriati.

abcNotValid

Nota

per supportare la convalida jQuery per le impostazioni locali non in lingua inglese che usano una virgola (",") per un separatore decimale, è necessario includere globalize.js e i file di impostazioni cultura/globalize.cultures.js specifici (da https://github.com/jquery/globalize ) e JavaScript per usare Globalize.parseFloat. Il codice seguente mostra le modifiche apportate al file Views\Movies\Edit.cshtml per funzionare con le impostazioni cultura "fr-FR":

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
    <script src="~/Scripts/globalize.js"></script>
    <script src="~/Scripts/globalize.culture.fr-FR.js"></script>
    <script>
        $.validator.methods.number = function (value, element) {
            return this.optional(element) ||
                !isNaN(Globalize.parseFloat(value));
        }
        $(document).ready(function () {
            Globalize.culture('fr-FR');
        });
    </script>
    <script>
        jQuery.extend(jQuery.validator.methods, {    
            range: function (value, element, param) {        
                //Use the Globalization plugin to parse the value        
                var val = $.global.parseFloat(value);
                return this.optional(element) || (
                    val >= param[0] && val <= param[1]);
            }
        });

    </script>
}

Il campo decimale può richiedere una virgola, non un separatore decimale. Come correzione temporanea, è possibile aggiungere l'elemento globalization al file radice dei progetti web.config. Il codice seguente mostra l'elemento globalization con le impostazioni cultura impostate su Stati Uniti inglese.

<system.web>
    <globalization culture ="en-US" />
    <!--elements removed for clarity-->
  </system.web>

Tutti i HttpGet metodi seguono un modello simile. Ottengono un oggetto filmato (o un elenco di oggetti, nel caso di Index) e passano il modello alla visualizzazione. Il Create metodo passa un oggetto filmato vuoto alla visualizzazione Create. Tutti i metodi che creano, modificano, eliminano o cambiano in altro modo i dati, eseguono questa operazione nell'overload HttpPost del metodo. La modifica dei dati in un metodo HTTP GET è un rischio per la sicurezza, come descritto nel post di blog ASP.NET MVC Tip #46 - Don't use Delete Links because they create Security Hole. La modifica dei dati in un metodo GET viola anche le procedure consigliate HTTP e il modello REST dell'architettura, che specifica che le richieste GET non devono modificare lo stato dell'applicazione. In altre parole, l'esecuzione di un'operazione GET deve essere sicura, senza effetti collaterali e non modificare dati persistenti.

Aggiunta di un metodo di ricerca e di una visualizzazione di ricerca

In questa sezione si aggiungerà un SearchIndex metodo di azione che consente di cercare film in base al genere o al nome. Sarà disponibile usando l'URL /Movies/SearchIndex . La richiesta visualizzerà un modulo HTML contenente elementi di input che un utente può immettere per cercare un filmato. Quando un utente invia il modulo, il metodo di azione otterrà i valori di ricerca pubblicati dall'utente e userà i valori per eseguire ricerche nel database.

Visualizzazione del modulo SearchIndex

Per iniziare, aggiungere un SearchIndex metodo di azione alla classe esistente MoviesController . Il metodo restituirà una visualizzazione contenente un modulo HTML. Ecco il codice:

public ActionResult SearchIndex(string searchString) 
{           
    var movies = from m in db.Movies 
                 select m; 
 
    if (!String.IsNullOrEmpty(searchString)) 
    { 
        movies = movies.Where(s => s.Title.Contains(searchString)); 
    } 
 
    return View(movies); 
}

La prima riga del SearchIndex metodo crea la query LINQ seguente per selezionare i film:

var movies = from m in db.Movies 
             select m;

La query viene definita a questo punto, ma non è ancora stata eseguita nell'archivio dati.

Se il searchString parametro contiene una stringa, la query movies viene modificata per filtrare il valore della stringa di ricerca, usando il codice seguente:

if (!String.IsNullOrEmpty(searchString)) 
{ 
    movies = movies.Where(s => s.Title.Contains(searchString)); 
}

Il codice s => s.Title precedente è un'espressione lambda. Le espressioni lambda vengono usate nelle query LINQ basate su metodo come argomenti per metodi dell'operatore di query standard, ad esempio il metodo Where usato nel codice precedente. Le query LINQ non vengono eseguite quando vengono definite o quando vengono modificate chiamando un metodo come Where o OrderBy. Al contrario, l'esecuzione di query viene posticipata, il che significa che la valutazione di un'espressione viene posticipata fino a quando il relativo valore realizzato non viene effettivamente eseguito l'iterazione o viene chiamato il ToList metodo . Nell'esempio SearchIndex la query viene eseguita nella vista SearchIndex. Per altre informazioni sull'esecuzione posticipata di query, vedere Esecuzione di query.

È ora possibile implementare la SearchIndex visualizzazione che visualizzerà il modulo all'utente. Fare clic con il pulsante destro del mouse all'interno del SearchIndex metodo e quindi scegliere Aggiungi visualizzazione. Nella finestra di dialogo Aggiungi visualizzazione specificare che si passerà un Movie oggetto al modello di visualizzazione come classe del modello di modello. Nell'elenco Modello di scaffolding scegliere Elenco, quindi fare clic su Aggiungi.

AddSearchView

Quando si fa clic sul pulsante Aggiungi , viene creato il modello di visualizzazione Views\Movies\SearchIndex.cshtml . Poiché è stato selezionato Elenco nell'elenco dei modelli di Scaffolding , Visual Studio ha generato automaticamente (scaffolding) un markup predefinito nella visualizzazione. Lo scaffolding ha creato un modulo HTML. Ha esaminato la classe e creato il codice per eseguire il Movie rendering <label> degli elementi per ogni proprietà della classe. L'elenco seguente mostra la visualizzazione Crea generata:

@model IEnumerable<MvcMovie.Models.Movie> 
 
@{ 
    ViewBag.Title = "SearchIndex"; 
} 
 
<h2>SearchIndex</h2> 
 
<p> 
    @Html.ActionLink("Create New", "Create") 
</p> 
<table> 
    <tr> 
        <th> 
            Title 
        </th> 
        <th> 
            ReleaseDate 
        </th> 
        <th> 
            Genre 
        </th> 
        <th> 
            Price 
        </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.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>

Eseguire l'applicazione e passare a /Movies/SearchIndex. Accodare una stringa di query, ad esempio ?searchString=ghost, all'URL. Vengono visualizzati i film filtrati.

SearchQryStr

Se si modifica la firma del SearchIndex metodo in modo che abbia un parametro denominato id, il id parametro corrisponderà al {id} segnaposto per le route predefinite impostate nel file Global.asax .

{controller}/{action}/{id}

Il metodo originale SearchIndex è simile al seguente:

public ActionResult SearchIndex(string searchString) 
{           
    var movies = from m in db.Movies 
                 select m; 
 
    if (!String.IsNullOrEmpty(searchString)) 
    { 
        movies = movies.Where(s => s.Title.Contains(searchString)); 
    } 
 
    return View(movies); 
}

Il metodo modificato SearchIndex sarà simile al seguente:

public ActionResult SearchIndex(string id) 
{ 
    string searchString = id; 
    var movies = from m in db.Movies 
                 select m; 
 
    if (!String.IsNullOrEmpty(searchString)) 
    { 
        movies = movies.Where(s => s.Title.Contains(searchString)); 
    } 
 
    return View(movies); 
}

È ora possibile passare il titolo della ricerca come dati di route (un segmento di URL), anziché come valore della stringa di query.

SearchRouteData

Tuttavia, non è possibile supporre che gli utenti modifichino l'URL ogni volta che desiderano cercare un film. Quindi ora si aggiungerà l'interfaccia utente per aiutarli a filtrare i film. Se è stata modificata la firma del SearchIndex metodo per verificare come passare il parametro ID associato a route, modificarla di nuovo in modo che il SearchIndex metodo accetta un parametro stringa denominato searchString:

public ActionResult SearchIndex(string searchString) 
{           
     var movies = from m in db.Movies 
                  select m; 
 
    if (!String.IsNullOrEmpty(searchString)) 
    { 
        movies = movies.Where(s => s.Title.Contains(searchString)); 
    } 
 
    return View(movies); 
}

Aprire il file Views\Movies\SearchIndex.cshtml e subito dopo @Html.ActionLink("Create New", "Create"), aggiungere quanto segue:

@using (Html.BeginForm()){    
         <p> Title: @Html.TextBox("SearchString")<br />  
         <input type="submit" value="Filter" /></p> 
        }

L'esempio seguente mostra una parte del file Views\Movies\SearchIndex.cshtml con il markup di filtro aggiunto.

@model IEnumerable<MvcMovie.Models.Movie> 
 
@{ 
    ViewBag.Title = "SearchIndex"; 
} 
 
<h2>SearchIndex</h2> 
 
<p> 
    @Html.ActionLink("Create New", "Create") 
     
     @using (Html.BeginForm()){    
         <p> Title: @Html.TextBox("SearchString") <br />   
         <input type="submit" value="Filter" /></p> 
        } 
</p>

L'helper Html.BeginForm crea un tag di apertura <form> . L'helper Html.BeginForm fa sì che il modulo invii se stesso quando l'utente invia il modulo facendo clic sul pulsante Filtro .

Eseguire l'applicazione e provare a cercare un film.

Screenshot dell'esecuzione dell'applicazione e del tentativo di ricerca di un filmato.

Non esiste alcun HttpPost overload del SearchIndex metodo . Non è necessario, perché il metodo non modifica lo stato dell'applicazione, filtrando semplicemente i dati.

È possibile aggiungere il metodo HttpPost SearchIndex seguente. In tal caso, l'action invoker corrisponde al HttpPost SearchIndex metodo e il HttpPost SearchIndex metodo verrebbe eseguito come illustrato nell'immagine seguente.

[HttpPost] 
public string SearchIndex(FormCollection fc, string searchString) 
{ 
    return "<h3> From [HttpPost]SearchIndex: " + searchString + "</h3>"; 
}

SearchPostGhost

Tuttavia, anche se si aggiunge questa versione HttpPost del metodo SearchIndex, esiste una limitazione sul modo sulla relativa implementazione. Si supponga che si desideri usare come segnalibro una ricerca specifica o inviare un collegamento agli amici su cui possono fare clic per visualizzare lo stesso elenco filtrato di film. Si noti che l'URL per la richiesta HTTP POST corrisponde all'URL della richiesta GET (localhost:xxxxx/Movies/SearchIndex). Non sono presenti informazioni di ricerca nell'URL stesso. Al momento, le informazioni sulla stringa di ricerca vengono inviate al server come valore del campo modulo. Ciò significa che non è possibile acquisire le informazioni di ricerca nel segnalibro o inviarle agli amici in un URL.

La soluzione consiste nell'usare un overload di BeginForm che specifica che la richiesta POST deve aggiungere le informazioni di ricerca all'URL e che deve essere indirizzata alla versione HttpGet del SearchIndex metodo . Sostituire il metodo senza BeginForm parametri esistente con quanto segue:

@using (Html.BeginForm("SearchIndex","Movies",FormMethod.Get))

BeginFormPost_SM

Ora, quando si invia una ricerca, l'URL contiene una stringa di query di ricerca. La ricerca passerà anche al metodo di azione HttpGet SearchIndex, anche se si dispone di un metodo HttpPost SearchIndex.

SearchIndexWithGetURL

Aggiunta della ricerca per genere

Se è stata aggiunta la HttpPost versione del SearchIndex metodo, eliminarla ora.

Successivamente, si aggiungerà una funzionalità per consentire agli utenti di cercare film per genere. Sostituire il metodo SearchIndex con il codice seguente:

public ActionResult SearchIndex(string movieGenre, string searchString) 
{ 
    var GenreLst = new List<string>(); 
 
    var GenreQry = from d in db.Movies 
                   orderby d.Genre 
                   select d.Genre; 
    GenreLst.AddRange(GenreQry.Distinct()); 
    ViewBag.movieGenre = new SelectList(GenreLst); 
 
    var movies = from m in db.Movies 
                 select m; 
 
    if (!String.IsNullOrEmpty(searchString)) 
    { 
        movies = movies.Where(s => s.Title.Contains(searchString)); 
    } 
 
    if (string.IsNullOrEmpty(movieGenre)) 
        return View(movies); 
    else 
    { 
        return View(movies.Where(x => x.Genre == movieGenre)); 
    } 
 
}

Questa versione del SearchIndex metodo accetta un parametro aggiuntivo, ovvero movieGenre. Le prime righe di codice creano un List oggetto per contenere generi cinematografici dal database.

Il codice seguente è una query LINQ che recupera tutti i generi dal database.

var GenreQry = from d in db.Movies 
                   orderby d.Genre 
                   select d.Genre;

Il codice usa il AddRange metodo della raccolta generica List per aggiungere tutti i generi distinti all'elenco. (Senza il Distinct modificatore, i generi duplicati verrebbero aggiunti, ad esempio, la commedia verrebbe aggiunta due volte nell'esempio). Il codice archivia quindi l'elenco di generi nell'oggetto ViewBag .

Nel codice seguente viene illustrato come controllare il movieGenre parametro . Se non è vuoto, il codice vincola ulteriormente la query movies per limitare i film selezionati al genere specificato.

if (string.IsNullOrEmpty(movieGenre)) 
        return View(movies); 
else 
{ 
    return View(movies.Where(x => x.Genre == movieGenre)); 
}

Aggiunta di markup alla visualizzazione SearchIndex per supportare la ricerca per genere

Aggiungere un Html.DropDownList helper al file Views\Movies\SearchIndex.cshtml , subito prima dell'helper TextBox . Il markup completato è illustrato di seguito:

<p> 
    @Html.ActionLink("Create New", "Create") 
    @using (Html.BeginForm("SearchIndex","Movies",FormMethod.Get)){     
         <p>Genre: @Html.DropDownList("movieGenre", "All")   
           Title: @Html.TextBox("SearchString")   
         <input type="submit" value="Filter" /></p> 
        } 
</p>

Eseguire l'applicazione e passare a /Movies/SearchIndex. Provare una ricerca per genere, in base al nome del film e per entrambi i criteri.

Screenshot dell'esecuzione dell'applicazione e del tentativo di ricerca in base al nome del film di genere e a entrambi i criteri.

In questa sezione sono stati esaminati i metodi di azione CRUD e le visualizzazioni generati dal framework. È stato creato un metodo di azione di ricerca e una visualizzazione che consentono agli utenti di eseguire ricerche in base al titolo e al genere del film. Nella sezione successiva verrà illustrato come aggiungere una proprietà al Movie modello e come aggiungere un inizializzatore che creerà automaticamente un database di test.