Skip to content

Commit

Permalink
Add array operators translation for lists
Browse files Browse the repository at this point in the history
  • Loading branch information
austindrenski committed Jul 27, 2018
1 parent 94033c0 commit fcacb79
Show file tree
Hide file tree
Showing 15 changed files with 2,368 additions and 391 deletions.
51 changes: 36 additions & 15 deletions doc/mapping/array.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,50 @@ PostgreSQL has the unique feature of supporting [*array data types*](https://www
# Mapping arrays

Simply define a regular .NET array or `List<>` property, and the provider
Npgsql maps PostgreSQL arrays to generic `T[]` and `List<T>` types:

```c#
public class Post
{
public int Id { get; set; }
public string Name { get; set; }
public string[] Tags { get; set; }
public List<string> AlternativeTags { get; set; }
public string[] SomeArray { get; set; }
public List<string> SomeList { get; set; }
}
```

The provider will create `text[]` columns for the above two properties, and will properly detect changes in them - if you load an array and change one of its elements, calling `SaveChanges()` will automatically update the row in the database accordingly.
The provider will create `text[]` columns for the above two properties, and will properly detect changes in themif you load an array and change one of its elements, calling `SaveChanges()` will automatically update the row in the database accordingly.

# Operation translation

The provider can also translate CLR array operations to the corresponding SQL operation; this allows you to efficiently work with arrays by evaluating operations in the database and avoids pulling all the data. The following table lists the range operations that currently get translated. If you run into a missing operation, please open an issue.

Note that operation translation on `List<>` is limited at this time, but will be improved in the future. It's recommended to use an array for now.

| C# expression | SQL generated by Npgsql |
|------------------------------------------------------------|-------------------------|
| `.Where(c => c.SomeArray[1] = "foo")` | [`WHERE "c"."SomeArray"[1] = 'foo'`](https://www.postgresql.org/docs/current/static/arrays.html#ARRAYS-ACCESSING)
| `.Where(c => c.SomeArray.SequenceEqual(new[] { 1, 2, 3 })` | [`WHERE "c"."SomeArray" = ARRAY[1, 2, 3])`](https://www.postgresql.org/docs/current/static/arrays.html)
| `.Where(c => c.SomeArray.Contains(3))` | [`WHERE 3 = ANY("c"."SomeArray")`](https://www.postgresql.org/docs/current/static/functions-comparisons.html#AEN21104)
| `.Where(c => c.SomeArray.Length == 3)` | [`WHERE array_length("c"."SomeArray, 1) = 3`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
The provider translates many operations on `T[]` and `List<T>` to corresponding SQL operations. This allows arrays to be worked with efficiently by evaluating operations in the database.

The following table lists the operations that are currently translated. If you run into a missing operation, please open an issue.

| C# expression | SQL generated by Npgsql |
|------------------------------------------------------------------|-------------------------|
| `.Where(c => c.SomeArray[0] == "foo")` | [`WHERE "c"."SomeArray"[1] = 'foo'`](https://www.postgresql.org/docs/current/static/arrays.html#ARRAYS-ACCESSING)
| `.Where(c => c.SomeList[0] == "foo")` | [`WHERE "c"."SomeList"[1] = 'foo'`](https://www.postgresql.org/docs/current/static/arrays.html#ARRAYS-ACCESSING)
| `.Where(c => c.SomeArray.ElementAt(0) == "foo")` | [`WHERE "c"."SomeArray"[1] = 'foo'`](https://www.postgresql.org/docs/current/static/arrays.html#ARRAYS-ACCESSING)
| `.Where(c => c.SomeList.ElementAt(0) == "foo")` | [`WHERE "c"."SomeList"[1] = 'foo'`](https://www.postgresql.org/docs/current/static/arrays.html#ARRAYS-ACCESSING)
| `.Select(x => Array.IndexOf(x.SomeArray, "foo"))` | [`SELECT COALESCE(array_position(x."SomeArray", 'foo'), -1)`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
| `.Select(x => x.SomeList.IndexOf("foo"))` | [`SELECT COALESCE(array_position(x."SomeList", 'foo'), -1)`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
| `.Where(x => x.SomeArray.Length == 1)` | [`WHERE array_length(x."SomeArray", 1) = 1`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
| `.Where(x => x.SomeList.Count == 1)` | [`WHERE array_length(x."SomeList", 1) = 1`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
| `.Where(x => x.SomeArray.Count() == 1)` | [`WHERE array_length(x."SomeArray", 1) = 1`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
| `.Where(x => x.SomeList.Count() == 1)` | [`WHERE array_length(x."SomeList", 1) = 1`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
| `.Where(x => x.SomeArray == x.SomeList)` | [`WHERE x."SomeArray" = x."SomeList"`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
| `.Where(x => x.SomeArray.Equals(x.SomeList))` | [`WHERE x."SomeArray" = x."SomeList"`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
| `.Where(x => x.SomeArray.SequenceEquals(x.SomeList))` | [`WHERE x."SomeArray" = x."SomeList"`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
| `.Where(x => x.SomeArray.Contains("foo"))` | [`WHERE 'foo' = ANY (x."SomeArray")`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
| `.Where(x => x.SomeList.Contains("foo"))` | [`WHERE 'foo' = ANY (x."SomeList")`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
| `.Select(x => x.SomeArray.Append("foo"))` | [`SELECT x."SomeArray" \|\| 'foo'`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
| `.Select(x => x.SomeList.Append("foo"))` | [`SELECT x."SomeList" \|\| 'foo'`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
| `.Select(x => x.SomeArray.Prepend("foo"))` | [`SELECT 'foo' \|\| x."SomeArray"`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
| `.Select(x => x.SomeList.Prepend("foo"))` | [`SELECT 'foo' \|\| x."SomeList"`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
| `.Select(x => x.SomeArray.Concat(x.SomeList))` | [`SELECT x."SomeArray" \|\| x."SomeList"`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
| `.Select(x => x.SomeList.Concat(x.SomeArray))` | [`SELECT x."SomeList" \|\| x."SomeArray"`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
| `.Select(x => EF.Functions.ArrayToString(x.SomeArray, ","))` | [`SELECT array_to_string(x."SomeArray", ',')`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
| `.Select(x => EF.Functions.ArrayToString(x.SomeList, ",", "*"))` | [`SELECT array_to_string(x."SomeList", ',', '*')`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
| `.Select(x => EF.Functions.Contains(x.SomeArray, x.SomeList))` | [`SELECT x."SomeArray" @> x."SomeList"`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
| `.Select(x => EF.Functions.ContainedBy(x.SomeArray, x.SomeList))`| [`SELECT x."SomeArray" <@ x."SomeList"`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
| `.Select(x => EF.Functions.Overlaps(x.SomeArray, x.SomeList))` | [`SELECT x."SomeArray" && x."SomeList"`](https://www.postgresql.org/docs/current/static/functions-array.html#ARRAY-FUNCTIONS-TABLE)
Loading

0 comments on commit fcacb79

Please sign in to comment.