Skip to content

Commit c5b80a1

Browse files
authored
Fix SQLite case sensitivity guidance (#35868)
1 parent 6108085 commit c5b80a1

File tree

7 files changed

+74
-12
lines changed

7 files changed

+74
-12
lines changed

aspnetcore/blazor/tutorials/movie-database-app/part-6.md

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,25 +58,36 @@ Change the `QuickGrid` component's <xref:Microsoft.AspNetCore.Components.QuickGr
5858

5959
The `movie => movie.Title!.Contains(...)` code is a *lambda expression*. Lambdas are used in method-based LINQ queries as arguments to standard query operator methods such as the <xref:System.Linq.Queryable.Where%2A> or <xref:System.String.Contains%2A> methods. LINQ queries aren't executed when they're defined or when they're modified by calling a method, such as <xref:System.Linq.Queryable.Where%2A>, <xref:System.String.Contains%2A>, or <xref:System.Linq.Queryable.OrderBy%2A>. Rather, query execution is deferred. The evaluation of an expression is delayed until its realized value is iterated.
6060

61-
The <xref:System.Data.Objects.DataClasses.EntityCollection%601.Contains%2A> method is run on the database, not in the C# code. The case sensitivity of the query depends on the database and the collation. For SQL Server, <xref:System.String.Contains%2A> maps to [SQL `LIKE`](/sql/t-sql/language-elements/like-transact-sql), which is case insensitive. SQLite with default collation provides a mixture of case-sensitive and case-insensitive filtering, depending on the query. The remainder of this tutorial assumes case-insensitive database collation.
62-
63-
To adopt case-insensitive collation when using SQLite (<xref:Microsoft.EntityFrameworkCore.SqliteDbContextOptionsBuilderExtensions.UseSqlite%2A> is called in `Program.cs`), open the `Data/BlazorWebAppMoviesContext.cs` file. Inside the `BlazorWebAppMoviesContext` class, add the following code:
64-
65-
```csharp
66-
protected override void OnModelCreating(ModelBuilder modelBuilder)
67-
{
68-
modelBuilder.UseCollation("SQL_Latin1_General_CP1_CS_AS");
69-
}
70-
```
61+
The <xref:System.Linq.Queryable.Where%2A> method is run on the database, not in the C# code. The case sensitivity of the query depends on the database and the collation. For SQL Server, <xref:System.String.Contains%2A> maps to [SQL `LIKE`](/sql/t-sql/language-elements/like-transact-sql), which is case insensitive. SQLite with default collation provides a mixture of case-sensitive and case-insensitive filtering, depending on the query.
7162

7263
Run the app and navigate to the movies `Index` page at `/movies`. The movies in the database load:
7364

7465
![Mad Max movies before filtering in the movies Index page](~/blazor/tutorials/movie-database-app/part-6/_static/before-filtering.png)
7566

67+
:::zone pivot="vs"
68+
7669
Append a query string to the URL in the address bar: `?titleFilter=road+warrior`. For example, the full URL appears as `https://localhost:7073/movies?titleFilter=road+warrior`, assuming the port number is `7073`. The filtered movie is displayed:
7770

7871
!['The Road Warrior' Mad Max movie filtered using a query string in the browser's address bar](~/blazor/tutorials/movie-database-app/part-6/_static/query-string-filter-result.png)
7972

73+
:::zone-end
74+
75+
:::zone pivot="vsc"
76+
77+
Append a query string to the URL in the address bar: `?titleFilter=Road+Warrior`. For example, the full URL appears as `https://localhost:7073/movies?titleFilter=Road+Warrior`, assuming the port number is `7073`. The filtered movie is displayed:
78+
79+
!['The Road Warrior' Mad Max movie filtered using a query string in the browser's address bar](~/blazor/tutorials/movie-database-app/part-6/_static/query-string-filter-result-sqlite.png)
80+
81+
:::zone-end
82+
83+
:::zone pivot="cli"
84+
85+
Append a query string to the URL in the address bar: `?titleFilter=Road+Warrior`. For example, the full URL appears as `https://localhost:7073/movies?titleFilter=Road+Warrior`, assuming the port number is `7073`. The filtered movie is displayed:
86+
87+
!['The Road Warrior' Mad Max movie filtered using a query string in the browser's address bar](~/blazor/tutorials/movie-database-app/part-6/_static/query-string-filter-result-sqlite.png)
88+
89+
:::zone-end
90+
8091
Next, give users a way to provide the `titleFilter` filter string via the component's UI. Add the following HTML under the H1 heading (`<h1>Index</h1>`). The following HTML reloads the page with the contents of the textbox as a query string value:
8192

8293
```html
@@ -108,6 +119,8 @@ Because the app is currently running with `dotnet watch`, saved changes are dete
108119

109120
:::zone-end
110121

122+
:::zone pivot="vs"
123+
111124
Type "`road warrior`" into the search box and select the **:::no-loc text="Search":::** button to filter the movies:
112125

113126
![Mad Max movies before filtering in the movies Index page. The search field has the value 'road warrior'.](~/blazor/tutorials/movie-database-app/part-6/_static/form-filter.png)
@@ -118,6 +131,36 @@ The result after searching on `road warrior`:
118131

119132
Notice that the search box loses the search value ("`road warrior`") when the movies are filtered. If you want to preserve the searched value, add the `data-permanent` attribute:
120133

134+
:::zone-end
135+
136+
:::zone pivot="vsc"
137+
138+
Type "`Road Warrior`" into the search box and select the **:::no-loc text="Search":::** button to filter the movies:
139+
140+
![Mad Max movies before filtering in the movies Index page. The search field has the value 'Road Warrior'.](~/blazor/tutorials/movie-database-app/part-6/_static/form-filter-sqlite.png)
141+
142+
The result after searching on `Road Warrior`:
143+
144+
!['The Road Warrior' Mad Max movie filtered using a GET request via an HTML form action](~/blazor/tutorials/movie-database-app/part-6/_static/form-filter-result-sqlite.png)
145+
146+
Notice that the search box loses the search value ("`Road Warrior`") when the movies are filtered. If you want to preserve the searched value, add the `data-permanent` attribute:
147+
148+
:::zone-end
149+
150+
:::zone pivot="cli"
151+
152+
Type "`Road Warrior`" into the search box and select the **:::no-loc text="Search":::** button to filter the movies:
153+
154+
![Mad Max movies before filtering in the movies Index page. The search field has the value 'Road Warrior'.](~/blazor/tutorials/movie-database-app/part-6/_static/form-filter-sqlite.png)
155+
156+
The result after searching on `Road Warrior`:
157+
158+
!['The Road Warrior' Mad Max movie filtered using a GET request via an HTML form action](~/blazor/tutorials/movie-database-app/part-6/_static/form-filter-result-sqlite.png)
159+
160+
Notice that the search box loses the search value ("`Road Warrior`") when the movies are filtered. If you want to preserve the searched value, add the `data-permanent` attribute:
161+
162+
:::zone-end
163+
121164
```diff
122165
- <form action="/movies" data-enhance>
123166
+ <form action="/movies" data-enhance data-permanent>
@@ -152,7 +195,6 @@ Stop the app by closing the browser's window and pressing <kbd>Ctrl</kbd>+<kbd>C
152195
* [LINQ documentation](/dotnet/csharp/programming-guide/concepts/linq/)
153196
* [Write C# LINQ queries to query data (C# documentation)](/dotnet/csharp/programming-guide/concepts/linq/query-syntax-and-method-syntax-in-linq)
154197
* [Lambda Expression (C# documentation](/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions)
155-
* [Collations and Case Sensitivity](/ef/core/miscellaneous/collations-and-case-sensitivity)
156198

157199
## Legal
158200

72.8 KB
Loading
121 KB
Loading
69.3 KB
Loading

aspnetcore/blazor/tutorials/movie-database-app/part-8.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,10 +191,30 @@ In its place, add the following Razor markup:
191191

192192
`@bind:event="oninput"` performs binding for the HTML's `oninput` event, which fires when the `<input>` element's value is changed as a direct result of a user typing in the search box. The QuickGrid is bound to `FilteredMovies`. As `titleFilter` changes with the value of the search box, rerendering the QuickGrid bound to the `FilteredMovies` method filters movie entities based on the updated value of `titleFilter`.
193193

194+
:::zone pivot="vs"
195+
194196
Run the app, type "`road warrior`" into the search field and notice how the QuickGrid is filtered for each character entered until *The Road Warrior* movie is left when the search field reaches "`road `" (&quot;:::no-loc text="road":::&quot; followed by a space).
195197

196198
![Movie list filtered to 'The Road Warrior' movie when the search box reaches 'road ' ('road' followed by a space).](~/blazor/tutorials/movie-database-app/part-8/_static/filtered-to-road-warrior.png)
197199

200+
:::zone-end
201+
202+
:::zone pivot="vsc"
203+
204+
Run the app, type "`Road Warrior`" into the search field and notice how the QuickGrid is filtered for each character entered until *The Road Warrior* movie is left when the search field reaches "`Road `" (&quot;:::no-loc text="Road":::&quot; followed by a space).
205+
206+
![Movie list filtered to 'The Road Warrior' movie when the search box reaches 'Road ' ('Road' followed by a space).](~/blazor/tutorials/movie-database-app/part-8/_static/filtered-to-road-warrior-sqlite.png)
207+
208+
:::zone-end
209+
210+
:::zone pivot="cli"
211+
212+
Run the app, type "`Road Warrior`" into the search field and notice how the QuickGrid is filtered for each character entered until *The Road Warrior* movie is left when the search field reaches "`Road `" (&quot;:::no-loc text="Road":::&quot; followed by a space).
213+
214+
![Movie list filtered to 'The Road Warrior' movie when the search box reaches 'Road ' ('Road' followed by a space).](~/blazor/tutorials/movie-database-app/part-8/_static/filtered-to-road-warrior-sqlite.png)
215+
216+
:::zone-end
217+
198218
Filtering database records is performed on the server, and the server interactively sends back the HTML to display over the same SignalR connection. The page doesn't reload. The user feels like their interactions with the page are running code on the client. Actually, the code is running the server.
199219

200220
Instead of an HTML form, submitting a GET request in this scenario could've also used JavaScript to submit the request to the server, either using the [Fetch API](https://developer.mozilla.org/docs/Web/API/Fetch_API)` or [XMLHttpRequest API](https://developer.mozilla.org/docs/Web/API/XMLHttpRequest). In most cases, JavaScript can be replaced by using Blazor and C# in an interactive component.
78.3 KB
Loading

aspnetcore/mvc/models/file-uploads.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1594,7 +1594,7 @@ Common storage options for files include:
15941594
* Services usually offer improved scalability and resiliency over on-premises solutions that are usually subject to single points of failure.
15951595
* Services are potentially lower cost in large storage infrastructure scenarios.
15961596

1597-
For more information, see [Quickstart: Use .NET to create a blob in object storage](/azure/storage/blobs/storage-quickstart-blobs-dotnet). The topic demonstrates <xref:Microsoft.Azure.Storage.File.CloudFile.UploadFromFileAsync*>, but <xref:Microsoft.Azure.Storage.File.CloudFile.UploadFromStreamAsync*> can be used to save a <xref:System.IO.FileStream> to blob storage when working with a <xref:System.IO.Stream>.
1597+
For more information, see [Quickstart: Use .NET to create a blob in object storage](/azure/storage/blobs/storage-quickstart-blobs-dotnet). The topic demonstrates <xref:Microsoft.Azure.Storage.File.CloudFile.UploadFromFileAsync%2A>, but <xref:Microsoft.Azure.Storage.File.CloudFile.UploadFromStreamAsync%2A> can be used to save a <xref:System.IO.FileStream> to blob storage when working with a <xref:System.IO.Stream>.
15981598

15991599
## File upload scenarios
16001600

0 commit comments

Comments
 (0)