Norm Example Project
Sample project with various examples of Norm usage and features. You can find the source code for this project on GitHub.
using System.Data.Common;
using Norm;
using Npgsql;
using static System.Console;
using TitleDescriptionYear = (string title, string description, int year);
using IdName = (int id, string name);
//
// Sample database: https://www.postgresqltutorial.com/postgresql-getting-started/postgresql-sample-database/
//
using var connection = new NpgsqlConnection("Server=localhost;Database=dvdrental;Port=5432;User Id=postgres;Password=postgres;");
// Iterate public static methods in Examples class
foreach (var method in typeof(Examples).GetMethods(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static))
{
ForegroundColor = ConsoleColor.Cyan;
WriteLine($"{method.Name}");
ResetColor();
method.Invoke(null, new object[] { connection });
WriteLine();
}
public class ExtraFilm : Film
{
public string Extra { get; set; } = "not-mapped";
}
public class Film
{
public int FilmId { get; set; }
public string Title { get; set; }
public int ReleaseYear { get; set; }
public decimal RentalRate { get; set; }
}
public class NonPublicFilm
{
public int FilmId { get; private set; } // not mapped
public string Title { get; protected set; } // not mapped
public int ReleaseYear { get; set; } // mapped
public decimal RentalRate { get; set; } // mapped
}
public class FilmDto
{
public int FilmId { get; set; }
public string Title { get; set; }
}
public class ActorDto
{
public int ActorId { get; set; }
public string Name { get; set; }
}
public static class Examples
{
public static void CountActors(DbConnection connection)
{
var count = connection.Read<int>("select count(*) from actor").Single();
WriteLine($"There are {count} actors in the database.");
}
public static void PrintTuples(DbConnection connection)
{
// tuples mapping
foreach (var tuple in connection.Read<string, string, int>("select title, description, release_year from film limit 3"))
{
Console.WriteLine("Title: {0}, Description: {1}, Year: {2}", tuple.Item1, tuple.Item2, tuple.Item3);
}
}
public static void PrintDeconstructedTuples(DbConnection connection)
{
// tuples deconstruction
foreach (var (title, description, year) in
connection.Read<string, string, int>("select title, description, release_year from film limit 3"))
{
WriteLine("Title: {0}, Description: {1}, Year: {2}", title, description, year);
}
}
public static void PrintNamedTuples(DbConnection connection)
{
// named tuples
foreach (var tuple in
connection
.Read<(string title, string description, int year)>("select title, description, release_year from film limit 3"))
{
WriteLine("Title: {0}, Description: {1}, Year: {2}", tuple.title, tuple.description, tuple.year);
}
}
public static void TitleDescriptionYearTupleAlias(DbConnection connection)
{
foreach (var tuple in connection.Read<TitleDescriptionYear>("select title, description, release_year from film limit 3"))
{
WriteLine("Title: {0}, Description: {1}, Year: {2}", tuple.title, tuple.description, tuple.year);
}
}
public static void IdNameTupleAlias(DbConnection connection)
{
foreach (var tuple in connection.Read<IdName>("select film_id, title from film limit 3"))
{
WriteLine("Film Id: {0}, Name: {1}", tuple.id, tuple.name);
}
}
public static void ConfigureGlobalSettings(DbConnection connection)
{
// set global command timeout to 60 seconds
// this call should be execute once from a program startup
NormOptions.Configure(options =>
{
options.CommandTimeout = 60;
});
var count = connection.Read<int>("select count(*) from actor").Single();
WriteLine($"There are {count} actors in the database. I executed this with command timeout of 60 seconds.");
}
public static void NonGeneric(DbConnection connection)
{
// dictionary where key is film_id and value is file title
var dict = connection
.Read("select film_id, title from film limit 3")
.ToDictionary(
tuples => (int)tuples.First().value,
tuples => tuples.Last().value?.ToString());
WriteLine("Dictionary first key-value {0}-{1} ", dict.Keys.First(), dict.Values.First());
}
public static void NonGenericAny(DbConnection connection)
{
WriteLine($"Film id=111 {(connection.Read("select 1 from film where film_id=111").Any() ? "exists" : "not exists")}");
}
public static void TuplesDictionary(DbConnection connection)
{
// dictionary where key is film_id and value is file title
var dict = connection
.Read<int, string>("select film_id, title from film limit 3")
.ToDictionary(
tuple => tuple.Item1,
tuple => tuple.Item2);
WriteLine("Dictionary first key-value {0}-{1} ", dict.Keys.First(), dict.Values.First());
}
public static void DoesFilmExists(DbConnection connection)
{
WriteLine("Film id {0} exists: {1} ", 999, connection.Read("select 1 from film where film_id = @id", 999).Any());
}
public static void UnamedNamedTuplesDictionary(DbConnection connection)
{
// dictionary where key is film_id and value is file title
var dict = connection
.Read<(int, string)>("select film_id, title from film limit 3")
.ToDictionary(
tuple => tuple.Item1,
tuple => tuple.Item2);
WriteLine("Dictionary first key-value {0}-{1} ", dict.Keys.First(), dict.Values.First());
}
public static void NamedTuplesDictionary(DbConnection connection)
{
// dictionary where key is film_id and value is file title
var dict = connection
.Read<(int id, string name)>("select film_id, title from film limit 3")
.ToDictionary(
tuple => tuple.id,
tuple => tuple.name);
WriteLine("Dictionary first key-value {0}-{1} ", dict.Keys.First(), dict.Values.First());
}
public static void PrintMultipleNamedTuples(DbConnection connection)
{
// deconstruction of named tuples
foreach (var (actor, film) in connection.Read<
(int id, string name),
(int id, string name)>(@"
select
actor_id, first_name || ' ' || last_name,
film_id, title
from
actor
join film_actor using (actor_id)
join film using (film_id)
limit 3"))
{
WriteLine("Actor: {0}-{1}, Film: {2}-{3}", actor.id, actor.name, film.id, film.name);
}
}
public static void PrintMultipleClassInstances(DbConnection connection)
{
// deconstruction of class instances
foreach (var (actor, film) in connection.Read<ActorDto, FilmDto>(@"
select
actor_id,
first_name || ' ' || last_name as name,
film_id,
title
from
actor
join film_actor using (actor_id)
join film using (film_id)
limit 3"))
{
WriteLine("Actor: {0}-{1}, Film: {2}-{3}", actor.ActorId, actor.Name, film.FilmId, film.Title);
}
}
public static void MixingNamedTupleAndClassInstances(DbConnection connection)
{
try
{
foreach (var (actor, film) in connection.Read<(int id, string name), FilmDto>(@"
select
actor_id,
first_name || ' ' || last_name as name,
film_id,
title
from
actor
join film_actor using (actor_id)
join film using (film_id)
limit 3"))
{
//...
}
}
catch (System.InvalidCastException e)
{
WriteLine("Mixing named tuples and class instances is not allowed: InvalidCastException: {0}", e.Message);
}
}
public static void MixingSimpleValuesAndClassInstances(DbConnection connection)
{
try
{
foreach (var (actorId, name, film) in connection.Read<int, string, FilmDto>(@"
select
actor_id,
first_name || ' ' || last_name as name,
film_id,
title
from
actor
join film_actor using (actor_id)
join film using (film_id)
limit 3"))
{
//...
}
}
catch (System.InvalidCastException e)
{
WriteLine("Mixing simple values and class instances is not allowed: InvalidCastException: {0}", e.Message);
}
}
public static void MixingSimpleValuesAndNamedTuples(DbConnection connection)
{
try
{
foreach (var (actorId, name, film) in connection.Read<int, string, (int id, string name)>(@"
select
actor_id,
first_name || ' ' || last_name as name,
film_id,
title
from
actor
join film_actor using (actor_id)
join film using (film_id)
limit 3"))
{
//...
}
}
catch (System.InvalidCastException e)
{
WriteLine("Mixing simple values and class instances is not allowed: InvalidCastException: {0}", e.Message);
}
}
public static void PrintFirstFilmFromClass(DbConnection connection)
{
var film = connection
.Read<Film>(@"
select film_id, title, release_year, rental_rate
from film
limit 1")
.Single();
WriteLine("Film: {0}-{1} Year: {2}, Rate: {3}",
film.FilmId, film.Title, film.ReleaseYear, film.RentalRate);
}
public static void PrintFirstFilmFromAnonymousClass(DbConnection connection)
{
var film = connection
.Read(new
{
filmId = default(int),
title = default(string),
releaseYear = default(int),
rentalRate = default(decimal)
}, @"
select film_id, title, release_year, rental_rate
from film
limit 1")
.Single();
WriteLine("Film: {0}-{1} Year: {2}, Rate: {3}",
film.filmId, film.title, film.releaseYear, film.rentalRate);
}
public static void PrintFirstFilmFromAnonymousClass2(DbConnection connection)
{
var film = connection
.Read(new
{
filmId = 1,
title = "",
releaseYear = 1,
rentalRate = 1m
}, @"
select film_id, title, release_year, rental_rate
from film
limit 1")
.Single();
WriteLine("Film: {0}-{1} Year: {2}, Rate: {3}",
film.filmId, film.title, film.releaseYear, film.rentalRate);
}
public static void PrintFirstFilmFromBlueprintInstance(DbConnection connection)
{
var instance = new Film();
var film = connection
.Read(instance, @"
select film_id, title, release_year, rental_rate
from film
limit 1")
.Single();
WriteLine("Film: {0}-{1} Year: {2}, Rate: {3}",
film.FilmId, film.Title, film.ReleaseYear, film.RentalRate);
}
public static void PrintFirstFilmReverseOrderFromClass(DbConnection connection)
{
var film = connection
.Read<Film>(@"
select rental_rate, release_year, title, film_id
from film
limit 1")
.Single();
WriteLine("Film: {0}-{1} Year: {2}, Rate: {3}",
film.FilmId, film.Title, film.ReleaseYear, film.RentalRate);
}
public static void PrintFirstFilmMapAllFromClass(DbConnection connection)
{
var film = connection
.Read<Film>("select * from film limit 1")
.Single();
WriteLine("Film: {0}-{1} Year: {2}, Rate: {3}",
film.FilmId, film.Title, film.ReleaseYear, film.RentalRate);
}
public static void PrintFilmsFromMappedClass(DbConnection connection)
{
foreach (var film in connection.Read<Film>(@"
select film_id, title, release_year, rental_rate
from film
limit 3"))
{
WriteLine("Film: {0}-{1} Year: {2}, Rate: {3}",
film.FilmId, film.Title, film.ReleaseYear, film.RentalRate);
}
}
public static void PrintFirstExtraFilmFromClass(DbConnection connection)
{
var film = connection
.Read<ExtraFilm>("select * from film limit 1")
.Single();
WriteLine("Film: {0}-{1} Extra: {2}", film.FilmId, film.Title, film.Extra);
}
public static void FilmFromClassSnakeCaseMappings(DbConnection connection)
{
// keep original names
NormOptions.Configure(options =>
{
options.KeepOriginalNames = true;
});
var film = connection
.Read<Film>("select * from film limit 1")
.Single();
WriteLine("Film id: {0}", film.FilmId); // film id defaults to 0
// use snake case
NormOptions.Configure(options =>
{
options.KeepOriginalNames = false;
});
film = connection
.Read<Film>("select * from film limit 1")
.Single();
WriteLine("Film id: {0}", film.FilmId); // film id is mapped
// fall-back to default
NormOptions.Configure(options =>
{
});
film = connection
.Read<Film>("select * from film limit 1")
.Single();
WriteLine("Film id: {0}", film.FilmId); // film id is mapped
}
public enum MyEnum { Value1, Value2, Value3 }
public static void ArraysAndEnumSimpleValue(DbConnection connection)
{
var t = connection
.Read<int[], int?[], MyEnum, MyEnum, MyEnum?, MyEnum?> (@"
select
array[1,2,3] as array_not_null,
array[1,null,3] as array_null,
'Value1' as text_enum_not_null,
0 as int_enum_not_null,
null::text as text_enum_null,
null::int as int_enum_null")
.Single();
WriteLine("{0} {1} {2} {3} {4} {5}",
string.Join(", ", t.Item1), string.Join(", ", t.Item2), t.Item3, t.Item4, t.Item5, t.Item6);
}
class MyComplexType
{
public int[] ArrayNotNull { get; set; }
public MyEnum TextEnumNotNull { get; set; }
public MyEnum IntEnumNotNull { get; set; }
public MyEnum? TextEnumNull { get; set; }
public MyEnum? IntEnumNull { get; set; }
public MyEnum[] TextEnumArray { get; set; }
public MyEnum[] IntEnumArray { get; set; }
}
public static void NameTupleArray(DbConnection connection)
{
var tuple = connection
.Read<(int[] intArray, string[] strArray)>("select array[1,2,3], array['a','b','c']")
.Single();
WriteLine("{0} {1}",
string.Join(", ", tuple.intArray),
string.Join(", ", tuple.strArray));
}
public static void ArraysAndEnumComplexType(DbConnection connection)
{
var instance = connection
.Read<MyComplexType>(@"
select
array[1,2,3] as array_not_null,
'Value1' as text_enum_not_null,
0 as int_enum_not_null,
null::text as text_enum_null,
null::int as int_enum_null,
array['Value1', 'Value2', 'Value2'] as text_enum_array,
array[0,1,2] as int_enum_array")
.Single();
WriteLine("{0} {1} {2} {3} {4} {5} {6}",
string.Join(", ", instance.ArrayNotNull),
instance.IntEnumNotNull,
instance.TextEnumNull,
instance.TextEnumNull,
instance.IntEnumNull,
string.Join(", ", instance.TextEnumArray),
string.Join(", ", instance.IntEnumArray));
}
public static void ReadMultipleBatch(DbConnection connection)
{
using var multiple = connection.Multiple(@"
select actor_id, first_name || ' ' || last_name as name from actor limit 3;
select film_id, title from film limit 3;
");
bool next;
var actors = multiple.Read<ActorDto>();
foreach (var actor in actors)
{
WriteLine("Actor: {0}-{1}", actor.ActorId, actor.Name);
}
next = multiple.Next();
WriteLine("Next: {0}", next);
var films = multiple.Read<FilmDto>();
foreach (var film in films)
{
WriteLine("Film: {0}-{1}", film.FilmId, film.Title);
}
next = multiple.Next();
WriteLine("Next: {0}", next);
}
public static void PrintNonPublicFilmFromClass(DbConnection connection)
{
var film = connection
.Read<NonPublicFilm>("select * from film limit 1")
.Single();
WriteLine("Film: {0}-{1} Year: {2}, Rate: {3}",
film.FilmId, film.Title, film.ReleaseYear, film.RentalRate);
// map private and protected members too
NormOptions.Configure(options =>
{
options.MapPrivateSetters = true;
});
film = connection
.Read<NonPublicFilm>("select * from film limit 1")
.Single();
WriteLine("Film: {0}-{1} Year: {2}, Rate: {3}",
film.FilmId, film.Title, film.ReleaseYear, film.RentalRate);
// fall-back to default
NormOptions.Configure(options =>
{
});
}
public static void DelayedExecution(DbConnection connection)
{
// create two iterators, no database calls yet
// iterator over int type
var result1 = connection.Read<int>("select count(*) from actor");
// iterator name-value array
var result2 = connection.Read("select title from film");
// Execute by initiating iterations
// execute count in database and print single result from count(*)
WriteLine($"There are {result1.Single()} actors in the database.");
// execute select in database, return all records and print iteration count
WriteLine($"There are {result2.Count()} films in the database.");
}
public static async Task DelayedExecutionAsync(DbConnection connection)
{
// create two iterators, no database calls yet
// async iterator over int type
var result1 = connection.ReadAsync<int>("select count(*) from actor");
// async iterator name-value array
var result2 = connection.ReadAsync("select title from film");
// Execute by initiating iterations
// execute count in database and print and await single async result from count(*)
WriteLine($"There are {await result1.SingleAsync()} actors in the database.");
// execute select in database, return all records and print and await iteration count async
WriteLine($"There are {await result2.CountAsync()} films in the database.");
}
}
using System.Data.Common;
using Norm;
using Npgsql;
using static System.Console;
using TitleDescriptionYear = (string title, string description, int year);
using IdName = (int id, string name);
//
// Sample database: https://www.postgresqltutorial.com/postgresql-getting-started/postgresql-sample-database/
//
using var connection = new NpgsqlConnection("Server=localhost;Database=dvdrental;Port=5432;User Id=postgres;Password=postgres;");
// Iterate public static methods in Examples class
foreach (var method in typeof(Examples).GetMethods(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static))
{
ForegroundColor = ConsoleColor.Cyan;
WriteLine($"{method.Name}");
ResetColor();
method.Invoke(null, new object[] { connection });
WriteLine();
}
public class ExtraFilm : Film
{
public string Extra { get; set; } = "not-mapped";
}
public class Film
{
public int FilmId { get; set; }
public string Title { get; set; }
public int ReleaseYear { get; set; }
public decimal RentalRate { get; set; }
}
public class NonPublicFilm
{
public int FilmId { get; private set; } // not mapped
public string Title { get; protected set; } // not mapped
public int ReleaseYear { get; set; } // mapped
public decimal RentalRate { get; set; } // mapped
}
public class FilmDto
{
public int FilmId { get; set; }
public string Title { get; set; }
}
public class ActorDto
{
public int ActorId { get; set; }
public string Name { get; set; }
}
public static class Examples
{
public static void CountActors(DbConnection connection)
{
var count = connection.Read<int>("select count(*) from actor").Single();
WriteLine($"There are {count} actors in the database.");
}
public static void PrintTuples(DbConnection connection)
{
// tuples mapping
foreach (var tuple in connection.Read<string, string, int>("select title, description, release_year from film limit 3"))
{
Console.WriteLine("Title: {0}, Description: {1}, Year: {2}", tuple.Item1, tuple.Item2, tuple.Item3);
}
}
public static void PrintDeconstructedTuples(DbConnection connection)
{
// tuples deconstruction
foreach (var (title, description, year) in
connection.Read<string, string, int>("select title, description, release_year from film limit 3"))
{
WriteLine("Title: {0}, Description: {1}, Year: {2}", title, description, year);
}
}
public static void PrintNamedTuples(DbConnection connection)
{
// named tuples
foreach (var tuple in
connection
.Read<(string title, string description, int year)>("select title, description, release_year from film limit 3"))
{
WriteLine("Title: {0}, Description: {1}, Year: {2}", tuple.title, tuple.description, tuple.year);
}
}
public static void TitleDescriptionYearTupleAlias(DbConnection connection)
{
foreach (var tuple in connection.Read<TitleDescriptionYear>("select title, description, release_year from film limit 3"))
{
WriteLine("Title: {0}, Description: {1}, Year: {2}", tuple.title, tuple.description, tuple.year);
}
}
public static void IdNameTupleAlias(DbConnection connection)
{
foreach (var tuple in connection.Read<IdName>("select film_id, title from film limit 3"))
{
WriteLine("Film Id: {0}, Name: {1}", tuple.id, tuple.name);
}
}
public static void ConfigureGlobalSettings(DbConnection connection)
{
// set global command timeout to 60 seconds
// this call should be execute once from a program startup
NormOptions.Configure(options =>
{
options.CommandTimeout = 60;
});
var count = connection.Read<int>("select count(*) from actor").Single();
WriteLine($"There are {count} actors in the database. I executed this with command timeout of 60 seconds.");
}
public static void NonGeneric(DbConnection connection)
{
// dictionary where key is film_id and value is file title
var dict = connection
.Read("select film_id, title from film limit 3")
.ToDictionary(
tuples => (int)tuples.First().value,
tuples => tuples.Last().value?.ToString());
WriteLine("Dictionary first key-value {0}-{1} ", dict.Keys.First(), dict.Values.First());
}
public static void NonGenericAny(DbConnection connection)
{
WriteLine($"Film id=111 {(connection.Read("select 1 from film where film_id=111").Any() ? "exists" : "not exists")}");
}
public static void TuplesDictionary(DbConnection connection)
{
// dictionary where key is film_id and value is file title
var dict = connection
.Read<int, string>("select film_id, title from film limit 3")
.ToDictionary(
tuple => tuple.Item1,
tuple => tuple.Item2);
WriteLine("Dictionary first key-value {0}-{1} ", dict.Keys.First(), dict.Values.First());
}
public static void DoesFilmExists(DbConnection connection)
{
WriteLine("Film id {0} exists: {1} ", 999, connection.Read("select 1 from film where film_id = @id", 999).Any());
}
public static void UnamedNamedTuplesDictionary(DbConnection connection)
{
// dictionary where key is film_id and value is file title
var dict = connection
.Read<(int, string)>("select film_id, title from film limit 3")
.ToDictionary(
tuple => tuple.Item1,
tuple => tuple.Item2);
WriteLine("Dictionary first key-value {0}-{1} ", dict.Keys.First(), dict.Values.First());
}
public static void NamedTuplesDictionary(DbConnection connection)
{
// dictionary where key is film_id and value is file title
var dict = connection
.Read<(int id, string name)>("select film_id, title from film limit 3")
.ToDictionary(
tuple => tuple.id,
tuple => tuple.name);
WriteLine("Dictionary first key-value {0}-{1} ", dict.Keys.First(), dict.Values.First());
}
public static void PrintMultipleNamedTuples(DbConnection connection)
{
// deconstruction of named tuples
foreach (var (actor, film) in connection.Read<
(int id, string name),
(int id, string name)>(@"
select
actor_id, first_name || ' ' || last_name,
film_id, title
from
actor
join film_actor using (actor_id)
join film using (film_id)
limit 3"))
{
WriteLine("Actor: {0}-{1}, Film: {2}-{3}", actor.id, actor.name, film.id, film.name);
}
}
public static void PrintMultipleClassInstances(DbConnection connection)
{
// deconstruction of class instances
foreach (var (actor, film) in connection.Read<ActorDto, FilmDto>(@"
select
actor_id,
first_name || ' ' || last_name as name,
film_id,
title
from
actor
join film_actor using (actor_id)
join film using (film_id)
limit 3"))
{
WriteLine("Actor: {0}-{1}, Film: {2}-{3}", actor.ActorId, actor.Name, film.FilmId, film.Title);
}
}
public static void MixingNamedTupleAndClassInstances(DbConnection connection)
{
try
{
foreach (var (actor, film) in connection.Read<(int id, string name), FilmDto>(@"
select
actor_id,
first_name || ' ' || last_name as name,
film_id,
title
from
actor
join film_actor using (actor_id)
join film using (film_id)
limit 3"))
{
//...
}
}
catch (System.InvalidCastException e)
{
WriteLine("Mixing named tuples and class instances is not allowed: InvalidCastException: {0}", e.Message);
}
}
public static void MixingSimpleValuesAndClassInstances(DbConnection connection)
{
try
{
foreach (var (actorId, name, film) in connection.Read<int, string, FilmDto>(@"
select
actor_id,
first_name || ' ' || last_name as name,
film_id,
title
from
actor
join film_actor using (actor_id)
join film using (film_id)
limit 3"))
{
//...
}
}
catch (System.InvalidCastException e)
{
WriteLine("Mixing simple values and class instances is not allowed: InvalidCastException: {0}", e.Message);
}
}
public static void MixingSimpleValuesAndNamedTuples(DbConnection connection)
{
try
{
foreach (var (actorId, name, film) in connection.Read<int, string, (int id, string name)>(@"
select
actor_id,
first_name || ' ' || last_name as name,
film_id,
title
from
actor
join film_actor using (actor_id)
join film using (film_id)
limit 3"))
{
//...
}
}
catch (System.InvalidCastException e)
{
WriteLine("Mixing simple values and class instances is not allowed: InvalidCastException: {0}", e.Message);
}
}
public static void PrintFirstFilmFromClass(DbConnection connection)
{
var film = connection
.Read<Film>(@"
select film_id, title, release_year, rental_rate
from film
limit 1")
.Single();
WriteLine("Film: {0}-{1} Year: {2}, Rate: {3}",
film.FilmId, film.Title, film.ReleaseYear, film.RentalRate);
}
public static void PrintFirstFilmFromAnonymousClass(DbConnection connection)
{
var film = connection
.Read(new
{
filmId = default(int),
title = default(string),
releaseYear = default(int),
rentalRate = default(decimal)
}, @"
select film_id, title, release_year, rental_rate
from film
limit 1")
.Single();
WriteLine("Film: {0}-{1} Year: {2}, Rate: {3}",
film.filmId, film.title, film.releaseYear, film.rentalRate);
}
public static void PrintFirstFilmFromAnonymousClass2(DbConnection connection)
{
var film = connection
.Read(new
{
filmId = 1,
title = "",
releaseYear = 1,
rentalRate = 1m
}, @"
select film_id, title, release_year, rental_rate
from film
limit 1")
.Single();
WriteLine("Film: {0}-{1} Year: {2}, Rate: {3}",
film.filmId, film.title, film.releaseYear, film.rentalRate);
}
public static void PrintFirstFilmFromBlueprintInstance(DbConnection connection)
{
var instance = new Film();
var film = connection
.Read(instance, @"
select film_id, title, release_year, rental_rate
from film
limit 1")
.Single();
WriteLine("Film: {0}-{1} Year: {2}, Rate: {3}",
film.FilmId, film.Title, film.ReleaseYear, film.RentalRate);
}
public static void PrintFirstFilmReverseOrderFromClass(DbConnection connection)
{
var film = connection
.Read<Film>(@"
select rental_rate, release_year, title, film_id
from film
limit 1")
.Single();
WriteLine("Film: {0}-{1} Year: {2}, Rate: {3}",
film.FilmId, film.Title, film.ReleaseYear, film.RentalRate);
}
public static void PrintFirstFilmMapAllFromClass(DbConnection connection)
{
var film = connection
.Read<Film>("select * from film limit 1")
.Single();
WriteLine("Film: {0}-{1} Year: {2}, Rate: {3}",
film.FilmId, film.Title, film.ReleaseYear, film.RentalRate);
}
public static void PrintFilmsFromMappedClass(DbConnection connection)
{
foreach (var film in connection.Read<Film>(@"
select film_id, title, release_year, rental_rate
from film
limit 3"))
{
WriteLine("Film: {0}-{1} Year: {2}, Rate: {3}",
film.FilmId, film.Title, film.ReleaseYear, film.RentalRate);
}
}
public static void PrintFirstExtraFilmFromClass(DbConnection connection)
{
var film = connection
.Read<ExtraFilm>("select * from film limit 1")
.Single();
WriteLine("Film: {0}-{1} Extra: {2}", film.FilmId, film.Title, film.Extra);
}
public static void FilmFromClassSnakeCaseMappings(DbConnection connection)
{
// keep original names
NormOptions.Configure(options =>
{
options.KeepOriginalNames = true;
});
var film = connection
.Read<Film>("select * from film limit 1")
.Single();
WriteLine("Film id: {0}", film.FilmId); // film id defaults to 0
// use snake case
NormOptions.Configure(options =>
{
options.KeepOriginalNames = false;
});
film = connection
.Read<Film>("select * from film limit 1")
.Single();
WriteLine("Film id: {0}", film.FilmId); // film id is mapped
// fall-back to default
NormOptions.Configure(options =>
{
});
film = connection
.Read<Film>("select * from film limit 1")
.Single();
WriteLine("Film id: {0}", film.FilmId); // film id is mapped
}
public enum MyEnum { Value1, Value2, Value3 }
public static void ArraysAndEnumSimpleValue(DbConnection connection)
{
var t = connection
.Read<int[], int?[], MyEnum, MyEnum, MyEnum?, MyEnum?> (@"
select
array[1,2,3] as array_not_null,
array[1,null,3] as array_null,
'Value1' as text_enum_not_null,
0 as int_enum_not_null,
null::text as text_enum_null,
null::int as int_enum_null")
.Single();
WriteLine("{0} {1} {2} {3} {4} {5}",
string.Join(", ", t.Item1), string.Join(", ", t.Item2), t.Item3, t.Item4, t.Item5, t.Item6);
}
class MyComplexType
{
public int[] ArrayNotNull { get; set; }
public MyEnum TextEnumNotNull { get; set; }
public MyEnum IntEnumNotNull { get; set; }
public MyEnum? TextEnumNull { get; set; }
public MyEnum? IntEnumNull { get; set; }
public MyEnum[] TextEnumArray { get; set; }
public MyEnum[] IntEnumArray { get; set; }
}
public static void NameTupleArray(DbConnection connection)
{
var tuple = connection
.Read<(int[] intArray, string[] strArray)>("select array[1,2,3], array['a','b','c']")
.Single();
WriteLine("{0} {1}",
string.Join(", ", tuple.intArray),
string.Join(", ", tuple.strArray));
}
public static void ArraysAndEnumComplexType(DbConnection connection)
{
var instance = connection
.Read<MyComplexType>(@"
select
array[1,2,3] as array_not_null,
'Value1' as text_enum_not_null,
0 as int_enum_not_null,
null::text as text_enum_null,
null::int as int_enum_null,
array['Value1', 'Value2', 'Value2'] as text_enum_array,
array[0,1,2] as int_enum_array")
.Single();
WriteLine("{0} {1} {2} {3} {4} {5} {6}",
string.Join(", ", instance.ArrayNotNull),
instance.IntEnumNotNull,
instance.TextEnumNull,
instance.TextEnumNull,
instance.IntEnumNull,
string.Join(", ", instance.TextEnumArray),
string.Join(", ", instance.IntEnumArray));
}
public static void ReadMultipleBatch(DbConnection connection)
{
using var multiple = connection.Multiple(@"
select actor_id, first_name || ' ' || last_name as name from actor limit 3;
select film_id, title from film limit 3;
");
bool next;
var actors = multiple.Read<ActorDto>();
foreach (var actor in actors)
{
WriteLine("Actor: {0}-{1}", actor.ActorId, actor.Name);
}
next = multiple.Next();
WriteLine("Next: {0}", next);
var films = multiple.Read<FilmDto>();
foreach (var film in films)
{
WriteLine("Film: {0}-{1}", film.FilmId, film.Title);
}
next = multiple.Next();
WriteLine("Next: {0}", next);
}
public static void PrintNonPublicFilmFromClass(DbConnection connection)
{
var film = connection
.Read<NonPublicFilm>("select * from film limit 1")
.Single();
WriteLine("Film: {0}-{1} Year: {2}, Rate: {3}",
film.FilmId, film.Title, film.ReleaseYear, film.RentalRate);
// map private and protected members too
NormOptions.Configure(options =>
{
options.MapPrivateSetters = true;
});
film = connection
.Read<NonPublicFilm>("select * from film limit 1")
.Single();
WriteLine("Film: {0}-{1} Year: {2}, Rate: {3}",
film.FilmId, film.Title, film.ReleaseYear, film.RentalRate);
// fall-back to default
NormOptions.Configure(options =>
{
});
}
public static void DelayedExecution(DbConnection connection)
{
// create two iterators, no database calls yet
// iterator over int type
var result1 = connection.Read<int>("select count(*) from actor");
// iterator name-value array
var result2 = connection.Read("select title from film");
// Execute by initiating iterations
// execute count in database and print single result from count(*)
WriteLine($"There are {result1.Single()} actors in the database.");
// execute select in database, return all records and print iteration count
WriteLine($"There are {result2.Count()} films in the database.");
}
public static async Task DelayedExecutionAsync(DbConnection connection)
{
// create two iterators, no database calls yet
// async iterator over int type
var result1 = connection.ReadAsync<int>("select count(*) from actor");
// async iterator name-value array
var result2 = connection.ReadAsync("select title from film");
// Execute by initiating iterations
// execute count in database and print and await single async result from count(*)
WriteLine($"There are {await result1.SingleAsync()} actors in the database.");
// execute select in database, return all records and print and await iteration count async
WriteLine($"There are {await result2.CountAsync()} films in the database.");
}
}
Comments