Skip to content

Commit

Permalink
WIP: Document Microsoft.Data.Sqlite
Browse files Browse the repository at this point in the history
  • Loading branch information
bricelam committed Dec 5, 2019
1 parent c43bd69 commit 0ff7792
Show file tree
Hide file tree
Showing 66 changed files with 2,486 additions and 12 deletions.
2 changes: 1 addition & 1 deletion .markdownlint.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"default": true,
"MD013": false,
"MD025": { "front_matter_title": "" },
"MD033": { "allowed_elements": ["sup", "sub", "nobe"] }
"MD033": { "allowed_elements": ["sup", "sub", "nobr", "span"] }
}
2 changes: 1 addition & 1 deletion entity-framework/docfx.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@
"ms.author": "avickers",
"feedback_system": "GitHub",
"feedback_github_repo": "aspnet/EntityFramework.Docs",
"feedback_product_url": "https://github.com/aspnet/EntityFrameworkCore/issues/new",
"feedback_product_url": "https://github.com/aspnet/EntityFrameworkCore/issues/new/choose",
"uhfHeaderId": "MSDocsHeader-DotNet"
},
"fileMetadata": {
Expand Down
3 changes: 2 additions & 1 deletion entity-framework/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@
href: core/modeling/keyless-entity-types.md
- name: Alternating models with same DbContext
href: core/modeling/dynamic-model.md
- name: Spatial Data (GIS)
- name: Spatial Data
displayName: GIS
href: core/modeling/spatial.md
- name: Relational database modeling
items:
Expand Down
57 changes: 55 additions & 2 deletions msdata-sqlite/TOC.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,55 @@
- name: Index
href: index.md
- name: Microsoft.Data.Sqlite
href: index.md
- name: Connection Strings
href: connection-strings.md
- name: Data Types
href: data-types.md
- name: Parameters
href: parameters.md
- name: Database Errors
displayName: Busy, Locked, Retries, Timeouts
href: errors.md
- name: Transactions
href: transactions.md
- name: Batching
href: batching.md
- name: Metadata
href: metadata.md
- name: SQLite Features
items:
- name: In-Memory Databases
href: memory.md
- name: Encryption
href: encryption.md
- name: Online Backup
href: backup.md
- name: User-Defined Functions
displayName: UDFs
href: udfs.md
- name: Custom SQLite Versions
href: custom-sqlite.md
- name: Collation
href: collation.md
- name: BLOB I/O
displayName: Streams
href: blob-io.md
- name: Interoperability
href: interop.md
- name: Extensions
href: extensions.md
- name: Limitations
items:
- name: ADO.NET
href: limitations.md
- name: Async
href: async.md
- name: Bulk Insert
href: bulk-insert.md
- name: Xamarin
href: xamarin.md
- name: Comparison to System.Data.SQLite
href: compare.md
- name: API Reference
href: /dotnet/api/?view=msdata-sqlite-3.0.0
- name: SQL Syntax (external)
href: https://www.sqlite.org/lang.html
15 changes: 15 additions & 0 deletions msdata-sqlite/async.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
title: Async Limitations - Microsoft.Data.Sqlite
author: bricelam
ms.date: 11/22/2019
---
# Async Limitations

SQLite doesn't support asynchronous I/O. Async ADO.NET methods will execute synchronously in Microsoft.Data.Sqlite. Avoid calling them.

Instead, use [write-ahead logging <span class="docon docon-navigate-external" aria-hidden="true" />](https://www.sqlite.org/wal.html) to improve performance and concurrency.

[!code-csharp[](../samples/msdata-sqlite/AsyncSample/Program.cs?name=snippet_WAL)]

> [!TIP]
> Write-ahead logging is enabled by default on databases created using [Entity Framework Core](/ef/core/).
12 changes: 12 additions & 0 deletions msdata-sqlite/backup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
title: Online Backup - Microsoft.Data.Sqlite
author: bricelam
ms.date: 11/22/2019
---
# Online Backup

SQLite can backup database files while the app is running. This functionality is available in Microsoft.Data.Sqlite as the [BackupDatabase](/dotnet/api/microsoft.data.sqlite.sqliteconnection.backupdatabase) method on SqliteConnection.

[!code-csharp[](../samples/msdata-sqlite/BackupSample/Program.cs?name=snippet_Backup)]

Currently, BackupDatabase will backup the database as quickly as possible blocking other connections from writing to the database. Issue [#13834](https://github.com/aspnet/EntityFrameworkCore/issues/13834) would provide an alternative API to backup the database in the background allowing other connections to interrupt the backup and write to the database. If you're interested in this, please provide feedback on the issue.
16 changes: 16 additions & 0 deletions msdata-sqlite/batching.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
title: Batching - Microsoft.Data.Sqlite
author: bricelam
ms.date: 11/22/2019
---
# Batching

SQLite doesn't natively support batching SQL statements together into a single command. But because there's no network involved, it wouldn't really help performance anyway. Microsoft.Data.Sqlite does however implements statement batching as a convenience to make it behave more like other ADO.NET providers.

When calling DbCommand.ExecuteReader(), statements are executed up to the first one that returns results. Calling DbDataReader.NextResult() continues executing statements until the next one that returns results or until it reaches the end of the batch. Calling DbDataReader.Dispose() or Close() will execute any remaining statements that haven't been consumed by NextResult(). If you don't dispose a data reader, the finalizer will try to execute the remaining statements, but any errors it encounters will be ignored. Because of this, it's very important to dispose DbDataReader objects when using batches.

[!code-csharp[](../samples/msdata-sqlite/BatchingSample/Program.cs?name=snippet_Batching)]

## See also

* [Bulk Insert](bulk-insert.md)
20 changes: 20 additions & 0 deletions msdata-sqlite/blob-io.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
title: BLOB I/O - Microsoft.Data.Sqlite
author: bricelam
ms.date: 11/22/2019
---
# BLOB I/O

You can reduce memory usage while reading and writing large objects by streaming the data into and out of the database. This can be especially useful when parsing or transforming the data.

Start by inserting a row as normal. Use the zeroblob() SQL function to allocate space in the database to hold the large object. The last_insert_rowid() function provides a convenient way to get its rowid.

[!code-csharp[](../samples/msdata-sqlite/StreamingSample/Program.cs?name=snippet_Insert)]

After inserting the row, open a stream to write the large object using [SqliteBlob](/dotnet/api/microsoft.data.sqlite.sqliteblob).

[!code-csharp[](../samples/msdata-sqlite/StreamingSample/Program.cs?name=snippet_Write)]

To stream the large object out of the database, you must select the rowid or one of its aliases as show here in addition to the large object's column. If you don't select the rowid, the entire object will be loaded into memory. If done correctly, the object returned by GetStream() will be a SqliteBlob.

[!code-csharp[](../samples/msdata-sqlite/StreamingSample/Program.cs?name=snippet_Read)]
10 changes: 9 additions & 1 deletion msdata-sqlite/breadcrumb/toc.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
- name: Docs
tocHref: /
topicHref: /
topicHref: /
items:
- name: .NET
tocHref: /dotnet/
topicHref: /dotnet/index
items:
- name: Microsoft.Data.Sqlite
tocHref: /msdata-sqlite/
topicHref: /msdata-sqlite/index
13 changes: 13 additions & 0 deletions msdata-sqlite/bulk-insert.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
title: Bulk Insert - Microsoft.Data.Sqlite
author: bricelam
ms.date: 11/22/2019
---
# Bulk Insert

SQLite doesn't have any special way to bulk insert data. To get optimal performance when inserting or updating data, ensure that you do the following.

1. Use a transaction.
2. Re-use the same parameterized command. Subsequent executions will reuse the compilation of the first one.

[!code-csharp[](../samples/msdata-sqlite/BulkInsertSample/Program.cs?name=snippet_BulkInsert)]
24 changes: 24 additions & 0 deletions msdata-sqlite/collation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
title: Collation - Microsoft.Data.Sqlite
author: bricelam
ms.date: 11/22/2019
---
# Collation

Collating sequences are used by SQLite when comparing TEXT values to determine order and equality. You can specify which collation to use when creating columns or per-operation in SQL queries. SQLite includes three collating sequences by default.

| Collation | Description |
| --------- | ----------------------------------------- |
| RTRIM | Ignores trailing white-space |
| NOCASE | Case-insensitive for ASCII characters A-Z |
| BINARY | Case-sensitive. Compares bytes directly |

## Custom collation

You can also define your own collating sequences or override the built-in ones using [CreateCollation()](/dotnet/api/microsoft.data.sqlite.sqliteconnection.createcollation). The following example shows overriding the NOCASE collation to support Unicode characters. The [full sample code](https://github.com/aspnet/EntityFramework.Docs/blob/master/samples/msdata-sqlite/CollationSample/Program.cs) is available on GitHub.

[!code-csharp[](../samples/msdata-sqlite/CollationSample/Program.cs?name=snippet_Collation)]

## See also

* [SQL Syntax <span class="docon docon-navigate-external" aria-hidden="true" />](https://www.sqlite.org/lang.html)
48 changes: 48 additions & 0 deletions msdata-sqlite/compare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
title: Comparison to System.Data.SQLite - Microsoft.Data.Sqlite
author: bricelam
ms.date: 11/12/2019
---
# Comparison to System.Data.SQLite

<!-- TODO: Write this -->

I haven't actually used Mono.Data.SqliteClient, but it's based on the same code (written by Robert Simpson) as System.Data.SQLite. There are three main differences between Microsoft.Data.Sqlite and System.Data.SQLite.

First, we don't aim to be a feature-complete ADO.NET provider. Microsoft.Data.Sqlite was created for .NET Core 1.0 when the goal was to create a lighter-weight, modernized version of .NET. That goal of .NET Core has largely been abandoned in favor of adding as many APIs as possible to make it easier to port from other .NET runtimes. However, the goal of Microsot.Data.Sqlite is still just to provide a basic ADO.NET implementation sufficient to support modern data access frameworks like EF Core, Dapper, etc. We tend not to add API for things that can be done using SQL. For example, see the table below for alternatives to connection string keywords.

<!-- TODO: More. Flags too? -->
Parameter | Comments
--- | ---
BinaryGUID | We always read and write Guid objects as BLOB. #273 & #191 are about using TEXT
CacheSize | You can send PRAGMA cache_size = \<pages>;
DateTimeFormat | We read using DateTime.Parse and write using yyyy-MM-dd HH:mm:ss.FFFFFFF
DateTimeKind | We ignore DateTime.DateTimeKind
FailIfMissing | You can use Mode = SqliteOpenMode.ReadWrite
JournalMode | You can send PRAGMA journal_mode = \<mode>;
LegacyFormat | You can send PRAGMA legacy_file_format = 1;
PageSize | You can send PRAGMA page_size = \<bytes>;
Pooling | We don't pool connections. It's not as important as on other databases where there's a network connection
SyncMode | You can send PRAGMA synchronous = \<mode>;
UseUTF16Encoding | You can send PRAGMA encoding = 'UTF-16';

The second big difference is that we're much closer to the native SQLite behavior. We don't try to compensate for any of SQLite's quirkiness. For example, System.Data.SQLite adds .NET semantics to column type names. They even have to parse every SQL statement before sending it to the native driver to handle a custom SQL statement for specifying the column type of results not coming directly from a table column (i.e. expressions in the SELECT clause). Instead, we embrace the fact that SQLite only supports four primitive types (INTEGER, REAL, TEXT, and BLOB) and implement ADO.NET APIs in a way that helps you coerce values between these and .NET types.

Finally, we weren't written 10 years ago. :-) This allow us to create more modern APIs that feel more natural in modern, idiomatic C#. The API for registering user-defined functions is the best example of this.

```cs
// System.Data.SQLite
connection.BindFunction(
new SQLiteFunctionAttribute("ceiling", 1, FunctionType.Scalar),
(Func<object[], object>)((object[] args) => Math.Celing((double)((object[])args[1])[0])),
null);

// Microsoft.Data.Sqlite
connection.CreateFunction(
"ceiling",
(double arg) => Math.Celing(arg));
```

<!-- TODO: No authorization https://github.com/aspnet/EntityFrameworkCore/issues/13835 -->
<!-- TODO: No data change notifications https://github.com/aspnet/EntityFrameworkCore/issues/13827 -->
<!-- TODO: No virtual table modules https://github.com/aspnet/EntityFrameworkCore/issues/13823 -->
132 changes: 132 additions & 0 deletions msdata-sqlite/connection-strings.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
---
title: Connection Strings - Microsoft.Data.Sqlite
author: bricelam
ms.date: 11/25/2019
---
# Connection Strings

A connection string is used to specify how to connect to the database. Connection strings in Microsoft.Data.Sqlite
follow the standard [ADO.NET syntax](/dotnet/framework/data/adonet/connection-strings) as a semicolon-separated list of
keywords and values.

## Keywords

The following connection string keyword can be used with Microsoft.Data.Sqlite.

### Data Source

The path to the database file. *DataSource* (without a space) and *Filename* are aliases of this keyword.

SQLite treats paths relative to the current working directory. Absolute paths can also be specified.

If **empty**, SQLite creates a temporary on-disk database that gets deleted when the connection is closed.

If `:memory:`, an in-memory database is used. See [In-Memory Databases](memory.md) for more details.

Paths that start with the `|DataDirectory|` substitution string are treated the same as relative paths. If set, paths are made relative to the DataDirectory application domain property value.

This keyword also supports [URI Filenames <span class="docon docon-navigate-external" aria-hidden="true" />](https://www.sqlite.org/uri.html).

### Mode

The connection mode.

| Value | Description |
| --------------- | -------------------------------------------------------------------------------------------------- |
| ReadWriteCreate | Opens the database for reading and writing, and creates it if it doesn't exist. This is the default. |
| ReadWrite | Opens the database for reading and writing. |
| ReadOnly | Opens the database in read-only mode. |
| Memory | Opens an in-memory database. |

### Cache

The caching mode used by the connection.

| Value | Description |
| ------- | ---------------------------------------------------------------------------------------------- |
| Default | Uses the default mode of the underlying SQLite library. This is the default. |
| Private | Each connection uses a private cache. |
| Shared | Connections share a cache. This mode can change the behavior of transaction and table locking. |

### Password

The encryption key. When specified, `PRAGMA key` is sent immediately after opening the connection.

> [!WARNING]
> Password has no effect when encryption isn't supported by the native SQLite library.
### Foreign Keys

A value indicating whether to enable foreign key constraints.

| Value | Description
| ------- | --- |
| True | Sends `PRAGMA foreign_keys = 1` immediately after opening the connection.
| False | Sends `PRAGMA foreign_keys = 0` immediately after opening the connection.
| (empty) | Doesn't send `PRAGMA foreign_keys`. This is the default. |

There is no need enable foreign keys if, like in e_sqlite3, SQLITE_DEFAULT_FOREIGN_KEYS was used to compile the native
SQLite library.

### Recursive Triggers

A value indicating whether to enable recursive triggers.

| Value | Description |
| ----- | --------------------------------------------------------------------------- |
| True | Sends `PRAGMA recursive_triggers` immediately after opening the connection. |
| False | Doesn't send `PRAGMA recursive_triggers`. This is the default. |

## Connection string builder

You can use [SqliteConnectionStringBuilder](/dotnet/api/microsoft.data.sqlite.sqliteconnectionstringbuilder) as a strongly-typed way of creating connection strings. It can also be used to prevent connection string injection attacks.

[!code-csharp[](../samples/msdata-sqlite/EncryptionSample/Program.cs?name=snippet_ConnectionStringBuilder)]

## Examples

### Basic

A basic connection string with a shared cache for improved concurrency.

```ConnectionString
Data Source=Application.db;Cache=Shared
```

### Encrypted

An encrypted database.

```ConnectionString
Data Source=Encrypted.db;Password=MyEncryptionKey
```

### Read-only

A read-only database that cannot be modified by the app.

```ConnectionString
Data Source=Reference.db;Mode=ReadOnly
```

### In-memory

A private in-memory database.

```ConnectionString
Data Source=:memory:
```

### Sharable in-memory

A sharable in-memory database identified by the name *Sharable*.

```ConnectionString
Data Source=Sharable;Mode=Memory;Cache=Shared
```

## See also

* [Connection Strings in ADO.NET](/dotnet/framework/data/adonet/connection-strings)
* [In-Memory Databases](memory.md)
* [Transactions](transactions.md)
Loading

0 comments on commit 0ff7792

Please sign in to comment.