Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

- Microsoft dependency injection / options #8

Merged
merged 19 commits into from
Sep 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 93 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,68 @@ Provides a thin abstraction over ADO.NET.

The `Shuttle.Core.Data` package provides a thin abstraction over ADO.NET by making use of the `DbProviderFactories` (see `Shuttle.Core.Data.SqlClient` for .Net Core Provider Factory adapter). Even though it provides object/relational mapping mechanisms it is in no way an ORM.

## Registration
## Configuration

You can register the relevant dependencies using `ComponentRegistryExtensions.RegisterDataAccess(IComponentRegistry)`.
### Connections

Connections may be added by providing all the required information:

```c#
services.AddDataAccess(builder =>
{
builder.AddConnection(name, providerName, connectionString);
});
```

A connection may also be added by omitting the `connectionString`, in which case it will be read from the `ConnectionStrings` section:

```c#
services.AddDataAccess(builder =>
{
builder.AddConnectionString(name, providerName);
});
```

### Options

The relevant options may be set using the builder:

```c#
services.AddDataAccess(builder =>
{
builder.Options.CommandTimeout = timeout;
builder.Options.DatabaseContextFactory = new DatabaseContextFactoryOptions
{
ConnectionStringName = "connection-string-name",
// -- or --
ProviderName = "provider-name",
ConnectionString = "connection-string"
}
});
```

The default JSON settings structure is as follows:

```json
{
"Shuttle": {
"DataAccess": {
"CommandTimeout": 25
}
}
}
```

# IDatabaseContextFactory

As per usual, in order to access a database, we need a database connection. A database connection is represented by a `IDatabaseContext` instance that may be obtained by using an instance of an `IDatabaseContextFactory` implementation.
In order to access a database we need a database connection. A database connection is represented by an `IDatabaseContext` instance that may be obtained by using an instance of an `IDatabaseContextFactory` implementation.

The `DatabaseContextFactory` implementation makes use of an `IDbConnectionFactory` implementation, that creates a `System.Data.IDbConnection` by using the provider name and connection string, an `IDbCommandFactory` that creates a `System.Data.IDbCommand` by using `IDbConnection` instance. The `DatabaseContextFactory` also requires an instance of a `IDatabaseContextCache` that stores connections and is assigned to the `DatabaseContext` in order to obtain the active connection.
The `DatabaseContextFactory` implementation makes use of an `IDbConnectionFactory` implementation which creates a `System.Data.IDbConnection` by using the provider name and connection string. An `IDbCommandFactory` creates a `System.Data.IDbCommand` by using an `IDbConnection` instance. The `DatabaseContextFactory` also requires an instance of an `IDatabaseContextCache` that stores connections and is assigned to the `DatabaseContext` in order to obtain the active connection.

``` c#
var factory = DatabaseContextFactory.Default();
var factory = provider.GetRequiredService<DatabaseContextFactory>();

using (var context = factory.Create("connectionStringName"))
using (var context = factory.Create("connection-name"))
{
// database interaction
}
Expand All @@ -41,28 +89,16 @@ using (var context = factory.Create(existingIDbConnection))
}
```

# IConfiguredDatabaseContextFactory

You can pre-configure your database context factory using this interface. If you typically connect to only one data source this may be helpful:

``` c#
IDatabaseContext Create();

void ConfigureWith(string connectionStringName);
void ConfigureWith(string providerName, string connectionString);
void ConfigureWith(IDbConnection dbConnection);
```

# IDatabaseGateway

The `DatabaseGateway` is used to execute `IQuery` instances in order return data from, or make changes to, the underlying data store. If there is no active open `IDatabaseContext` returned by the `DatabaseContext.Current` and `InvalidOperationException` will be thrown.

The following section each describe the methods available in the `IDatabaseGateway` interface.

## GetReaderUsing
## GetReader

``` c#
IDataReader GetReaderUsing(IQuery query);
IDataReader GetReader(IQuery query);
```

Returns an `IDataReader` instance for the given `select` statement:
Expand All @@ -71,16 +107,16 @@ Returns an `IDataReader` instance for the given `select` statement:
var factory = DatabaseContextFactory.Default();
var gateway = new DatabaseGateway();

using (var context = factory.Create("connectionStringName"))
using (var context = factory.Create("connection-name"))
{
var reader = gateway.GetReaderUsing(RawQuery.Create("select Id, Username from dbo.Member"));
var reader = gateway.GetReader(RawQuery.Create("select Id, Username from dbo.Member"));
}
```

## ExecuteUsing
## Execute

``` c#
int ExecuteUsing(IQuery query);
int Execute(IQuery query);
```

Executes the given query and returns the number of rows affected:
Expand All @@ -89,40 +125,40 @@ Executes the given query and returns the number of rows affected:
var factory = DatabaseContextFactory.Default();
var gateway = new DatabaseGateway();

using (var context = factory.Create("connectionStringName"))
using (var context = factory.Create("connection-name"))
{
gateway.ExecuteUsing(RawQuery.Create("delete from dbo.Member where Username = 'mr.resistor'"));
gateway.Execute(RawQuery.Create("delete from dbo.Member where Username = 'mr.resistor'"));
}
```

## GetScalarUsing<T>
## GetScalar

``` c#
T GetScalarUsing<T>(IQuery query);
```c#
T GetScalar<T>(IQuery query);
```

Get the scalar value returned by the `select` query. The query shoud return only one value (scalar):

``` c#
```c#
var factory = DatabaseContextFactory.Default();
var gateway = new DatabaseGateway();

using (var context = factory.Create("connectionStringName"))
using (var context = factory.Create("connection-name"))
{
var username = gateway.GetScalarUsing<string>(
var username = gateway.GetScalar<string>(
RawQuery.Create("select Username from dbo.Member where Id = 10")
);

var id = gateway.GetScalarUsing<int>(
var id = gateway.GetScalar<int>(
RawQuery.Create("select Id from dbo.Member where Username = 'mr.resistor'")
);
}
```

## GetDataTableFor
## GetDataTable

``` c#
DataTable GetDataTableFor(IQuery query);
DataTable GetDataTable(IQuery query);
```

Returns a `DataTable` containing the rows returned for the given `select` statement.
Expand All @@ -131,16 +167,16 @@ Returns a `DataTable` containing the rows returned for the given `select` statem
var factory = DatabaseContextFactory.Default();
var gateway = new DatabaseGateway();

using (var context = factory.Create("connectionStringName"))
using (var context = factory.Create("connection-name"))
{
var table = gateway.GetDataTableFor(RawQuery.Create("select Id, Username from dbo.Member"));
var table = gateway.GetDataTable(RawQuery.Create("select Id, Username from dbo.Member"));
}
```

## GetRowsUsing
## GetRows

``` c#
IEnumerable<DataRow> GetRowsUsing(IQuery query);
IEnumerable<DataRow> GetRows(IQuery query);
```

Returns an enumerable containing the `DataRow` instances returned for a `select` query:
Expand All @@ -149,17 +185,16 @@ Returns an enumerable containing the `DataRow` instances returned for a `select`
var factory = DatabaseContextFactory.Default();
var gateway = new DatabaseGateway();

using (var context = factory.Create("connectionStringName"))
using (var context = factory.Create("connection-name"))
{
var rows = gateway.GetRowsUsing(RawQuery.Create("select Id, Username from dbo.Member"));
var rows = gateway.GetRows(RawQuery.Create("select Id, Username from dbo.Member"));
}
```


## GetSingleRowUsing
## GetRow

``` c#
DataRow GetSingleRowUsing(IQuery query);
DataRow GetRow(IQuery query);
```

Returns a single `DataRow` containing the values returned for a `select` statement that returns exactly one row:
Expand All @@ -168,51 +203,51 @@ Returns a single `DataRow` containing the values returned for a `select` stateme
var factory = DatabaseContextFactory.Default();
var gateway = new DatabaseGateway();

using (var context = factory.Create("connectionStringName"))
using (var context = factory.Create("connection-name"))
{
var row = gateway.GetSingleRowUsing(
var row = gateway.GetRow(
RawQuery.Create("select Id, Username, EMail, DateActivated from dbo.Member where Id = 10")
);
}
```

# IDataRepository<T>
# IDataRepository

An `IDataRepository<T>` implementation is responsible for returning a hydrated object. To this end you make use of the `DataReposity<T>` class that takes a `IDatabaseGateway` instance along with a `IDataRowMapper<T>` used to create the hydrated instance.

The following methods can be used to interact with your object type.

## FetchAllUsing
## FetchItems

``` c#
IEnumerable<T> FetchAllUsing(IQuery query);
IEnumerable<T> FetchItems(IQuery query);
```

Uses the `select` clause represented by the `IQuery` instance to create a list of objects of type `T`. The `select` clause will need to select all the required columns and will, typically, return more than one instance.

## FetchItemUsing
## FetchItem

``` c#
T FetchItemUsing(IQuery query);
T FetchItem(IQuery query);
```

Returns a single object instance of type `T` that is hydrated using the data returned from the `select` clause represented by the `IQuery` instance.

## FetchMappedRowsUsing
## FetchMappedRows

``` c#
IEnumerable<MappedRow<T>> FetchMappedRowsUsing(IQuery query);
IEnumerable<MappedRow<T>> FetchMappedRows(IQuery query);
```

This is similar to the `FetchAllUsing` method but instead returns a list of `MappedRow<T>` instances. Uses the `select` clause represented by the `IQuery` instance to create a list of `MappedRow` instances of type `T`. The `select` clause will need to select all the required columns and will, typically, return more than one instance.
This is similar to the `FetchItems` method but instead returns a list of `MappedRow<T>` instances. Uses the `select` clause represented by the `IQuery` instance to create a list of `MappedRow` instances of type `T`. The `select` clause will need to select all the required columns and will, typically, return more than one instance.

## FetchMappedRowUsing
## FetchMappedRow

``` c#
MappedRow<T> FetchMappedRowUsing(IQuery query);
MappedRow<T> FetchMappedRow(IQuery query);
```

Similar to the `FetchItemUsing` method but instead return a `MappedRow<T>` instance that is hydrated using the data returned from the `select` clause represented by the `IQuery` instance.
Similar to the `FetchItem` method but instead return a `MappedRow<T>` instance that is hydrated using the data returned from the `select` clause represented by the `IQuery` instance.

## Contains

Expand Down Expand Up @@ -299,7 +334,7 @@ public T MapFrom(DataRow row)

This will return the typed value of the specified column as contained in the passed-in `DataRow`.

# IDataRowMapper<T>
# IDataRowMapper

You use this interface to implement a mapper for a `DataRow` that will result in an object of type `T`:

Expand Down
10 changes: 0 additions & 10 deletions Shuttle.Core.Data.Tests/App.config

This file was deleted.

23 changes: 0 additions & 23 deletions Shuttle.Core.Data.Tests/ConnectionConfigurationProviderFixture.cs

This file was deleted.

Loading