Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/khellang/efcore.sqlite.nodatime

Adds support for NodaTime types when using SQLite with Entity Framework Core.
https://github.com/khellang/efcore.sqlite.nodatime

c-sharp database dotnet dotnet-core entity-framework nodatime nodatime-types orm sqlite

Last synced: about 1 month ago
JSON representation

Adds support for NodaTime types when using SQLite with Entity Framework Core.

Awesome Lists containing this project

README

        

# EFCore.Sqlite.NodaTime

![Build](https://github.com/khellang/EFCore.Sqlite.NodaTime/workflows/Build/badge.svg)

Adds support for [NodaTime](https://github.com/nodatime/nodatime) types when using [SQLite](https://sqlite.org/) with [Entity Framework Core](https://github.com/dotnet/efcore).

## Installation

[![NuGet](https://img.shields.io/nuget/v/EntityFrameworkCore.Sqlite.NodaTime)](https://www.nuget.org/packages/EntityFrameworkCore.Sqlite.NodaTime)

Install the latest package from [NuGet](https://www.nuget.org/packages/EntityFrameworkCore.Sqlite.NodaTime).

## Getting Started

If you're using Entity Framework Core without Dependency Injection, you can call `UseNodaTime` inside the `OnConfiguring` method in your `DbContext` class:

```csharp
public class MyDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite("", x => x.UseNodaTime());
}
}
```

Otherwise, you should call `UseNodaTime` when adding the `DbContext` to your service collection:

```csharp
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext(options =>
options.UseSqlite("", x => x.UseNodaTime()));
}
}
```

And that's it. You can now use NodaTime types in your entities and perform server-side queries on them! :sparkles:

## Supported Types

The following NodaTime types are currently supported:

| NodaTime Type | SQLite Type | SQLite Format |
|---------------|-------------|---------------|
| `Instant` | `TEXT` | `YYYY-MM-DD HH:MM:SS.SSS` |
| `LocalDateTime` | `TEXT` | `YYYY-MM-DD HH:MM:SS.SSS` |
| `LocalDate` | `TEXT` | `YYYY-MM-DD` |
| `LocalTime` | `TEXT` | `HH:MM:SS.SSS` |

# Supported Properties

| NodaTime Property | Generated SQL | Notes |
|-------------------|--------------|-------|
| `Year` | `strftime('%Y', )` | The value is cast to `INTEGER` for comparison. |
| `Month` | `strftime('%m', )` | The value is cast to `INTEGER` for comparison. |
| `Day` | `strftime('%d', )` | The value is cast to `INTEGER` for comparison. |
| `Hour` | `strftime('%H', )` | The value is cast to `INTEGER` for comparison. |
| `Minute` | `strftime('%M', )` | The value is cast to `INTEGER` for comparison. |
| `Second` | `strftime('%S', )` | The value is cast to `INTEGER` for comparison. |
| `DayOfYear` | `strftime('%j', )` | The value is cast to `INTEGER` for comparison.|
| `DayOfWeek` | `strftime('%w', )` | The value is cast to `INTEGER` for comparison. As NodaTime's `IsoDayOfWeek` enum doesn't match SQLite's day of week, additional SQL is emitted to convert `Sunday` to the correct value. |
| `Date` | `date()` | |
| `TimeOfDay` | `strftime('%H:%M:%f', )` | In order to support fractional seconds to fully roundtrip `LocalTime`, a custom format string is used instead of using `time()`. |

## Supported Methods

| NodaTime Method | Generated SQL |
|-----------------|---------------|
| `SystemClock.Instance.GetCurrentInstant()` | `strftime('%Y-%m-%d %H:%M:%f', 'now')` |
| `LocalDate.PlusYears` | `date(, '+n years')` |
| `LocalDate.PlusMonths` | `date(, '+n months')` |
| `LocalDate.PlusWeeks` | `date(, '+n*7 days')` |
| `LocalDate.PlusDays` | `date(, '+n days')` |
| `LocalDate.ToDateOnly` | `date()` |
| `LocalDate.ToDateTimeUnspecified` | `date()` |
| `LocalTime.PlusHours` | `strftime('%H:%M:%f', , '+n hours')` |
| `LocalTime.PlusMinutes` | `strftime('%H:%M:%f', , '+n minutes')` |
| `LocalTime.PlusSeconds` | `strftime('%H:%M:%f', , '+n seconds')` |
| `LocalTime.PlusMilliseconds` | `strftime('%H:%M:%f', , '+0.n seconds')` |
| `LocalTime.ToTimeOnly` | `strftime('%H:%M:%f', )` |
| `LocalDateTime.PlusYears` | `strftime('%Y-%m-%d %H:%M:%f',, '+n years')` |
| `LocalDateTime.PlusMonths` | `strftime('%Y-%m-%d %H:%M:%f',, '+n months')` |
| `LocalDateTime.PlusWeeks` | `strftime('%Y-%m-%d %H:%M:%f',, '+n*7 days')` |
| `LocalDateTime.PlusDays` | `strftime('%Y-%m-%d %H:%M:%f',, '+n days')` |
| `LocalDateTime.PlusHours` | `strftime('%Y-%m-%d %H:%M:%f', , '+n hours')` |
| `LocalDateTime.PlusMinutes` | `strftime('%Y-%m-%d %H:%M:%f', , '+n minutes')` |
| `LocalDateTime.PlusSeconds` | `strftime('%Y-%m-%d %H:%M:%f', , '+n seconds')` |
| `LocalDateTime.PlusMilliseconds` | `strftime('%Y-%m-%d %H:%M:%f', , '+0.n seconds')` |
| `LocalDateTime.ToDateTimeUnspecified` | `strftime('%Y-%m-%d %H:%M:%f', )` |

When these methods are chained, all modifiers will be added to the same function call, like this:

```csharp
context.NodaTime.Select(x => x.LocalDateTime.PlusMonths(2).PlusDays(2).PlusHours(2).PlusSeconds(2))
```

Results in the following SQL:

```sql
SELECT strftime('%Y-%m-%d %H:%M:%f', "n"."LocalDateTime", '+2 months', '+2 days', '+2 hours', '+2 seconds')
```