OrmLite's Expression support satisfies the most common RDBMS queries with a strong-typed API. For more complex queries you can easily fall back to raw SQL where the Custom SQL APIs let you map custom SqlExpressions into different responses:
var q = db.From<Person>()
.Where(x => x.Age < 50)
.Select("*");
List<Person> results = db.SqlList<Person>(q);
List<Person> results = db.SqlList<Person>(
"SELECT * FROM Person WHERE Age < @age", new { age=50});
List<string> results = db.SqlColumn<string>(db.From<Person>().Select(x => x.LastName));
List<string> results = db.SqlColumn<string>("SELECT LastName FROM Person");
HashSet<int> results = db.ColumnDistinct<int>(db.From<Person>().Select(x => x.Age));
HashSet<int> results = db.ColumnDistinct<int>("SELECT Age FROM Person");
var q = db.From<Person>()
.Where(x => x.Age < 50)
.Select(Sql.Count("*"));
int result = db.SqlScalar<int>(q);
int result = db.SqlScalar<int>("SELECT COUNT(*) FROM Person WHERE Age < 50");
Custom SQL with Typed SqlExpression​
Using a typed SQL Expression with a mix of typed an custom SQL Expressions:
var q = db.From<Person>();
q.Where("Age < {0}", 50);
List<Person> results = db.Select(q)
var q = db.From<Person>().Where("Age < {0}", 50);
string sql = q.ToSelectStatement();
List<Person> results = db.Select(sql, q.Params);
TIP
If your custom SQL Expression fails because it contains raw SQL with comments or write commands you can use Unsafe*
APIs to by-pass SQL Validation, e.g. q.UnsafeWhere(rawSql)
Custom Selects​
public record CustomPoco(int Year, string Max);
var upperNamesWithA = db.SqlColumn<string>(
"SELECT upper(Name) FROM Track WHERE instr(Name,'a') > 0");
var meta = db.SqlList<CustomPoco>(
"SELECT DISTINCT Year % 10 as Year, hex(Year % 10) as Hex FROM Track");
db.ExecuteSql("ALTER TABLE Track ADD Rand INT default 0");
db.ExecuteSql("UPDATE Track SET Rand = abs(random()) % 1000");
var trackRandValues = db.Dictionary<string,int>("SELECT Name, Rand FROM Track");
var maxRand = db.SqlScalar<int>("SELECT MAX(Rand) FROM Track");
Custom Insert and Updates​
Db.ExecuteSql("INSERT INTO page_stats (ref_id, fav_count) VALUES (@refId, @favCount)",
new { refId, favCount })
//Async:
Db.ExecuteSqlAsync("UPDATE page_stats SET view_count = view_count + 1 WHERE id = @id", new { id })
INSERT INTO SELECT​
You can use OrmLite's Typed SqlExpression
to create a subselect expression that you can use to create and execute a
typed INSERT INTO SELECT SqlExpression
with:
var q = db.From<User>()
.Where(x => x.UserName == "UserName")
.Select(x => new {
x.UserName,
x.Email,
GivenName = x.FirstName,
Surname = x.LastName,
FullName = x.FirstName + " " + x.LastName
});
var id = db.InsertIntoSelect<CustomUser>(q)
Foreign Key attribute for referential actions on Update/Deletes​
Creating a foreign key in OrmLite can be done by adding [References(typeof(ForeignKeyTable))]
on the relation property,
which will result in OrmLite creating the Foreign Key relationship when it creates the DB table with db.CreateTable<Poco>
.
Additional fine-grain options and behaviour are available in the [ForeignKey]
attribute which will let you specify the desired behaviour when deleting or updating related rows in Foreign Key tables.
An example of a table with the different available options:
public class TableWithAllCascadeOptions
{
[AutoIncrement] public int Id { get; set; }
[References(typeof(ForeignKeyTable1))]
public int SimpleForeignKey { get; set; }
[ForeignKey(typeof(ForeignKeyTable2), OnDelete = "CASCADE", OnUpdate = "CASCADE")]
public int? CascadeOnUpdateOrDelete { get; set; }
[ForeignKey(typeof(ForeignKeyTable3), OnDelete = "NO ACTION")]
public int? NoActionOnCascade { get; set; }
[Default(typeof(int), "17")]
[ForeignKey(typeof(ForeignKeyTable4), OnDelete = "SET DEFAULT")]
public int SetToDefaultValueOnDelete { get; set; }
[ForeignKey(typeof(ForeignKeyTable5), OnDelete = "SET NULL")]
public int? SetToNullOnDelete { get; set; }
}
System Variables and Default Values​
To provide richer support for non-standard default values, each RDBMS Dialect Provider contains a
OrmLiteDialectProvider.Variables
placeholder dictionary for storing common, but non-standard RDBMS functionality.
We can use this to define non-standard default values, in a declarative way, that works across all supported RDBMS's
like automatically populating a column with the RDBMS UTC Date when Inserted with a default(T)
Value:
public class Poco
{
[Default(OrmLiteVariables.SystemUtc)] //= {SYSTEM_UTC}
public DateTime CreatedTimeUtc { get; set; }
}
OrmLite variables need to be surrounded with {}
braces to identify that it's a placeholder variable, e.g {SYSTEM_UTC}
.
The ForeignKeyTests show the resulting behaviour with each of these configurations in more detail.
INFO
Note: Only supported on RDBMS's with foreign key/referential action support, e.g. Sql Server, PostgreSQL, MySQL. Otherwise they're ignored.
Custom SQL using PostgreSQL Arrays​
The PgSql.Array()
provides a typed API for generating PostgreSQL Array Expressions, e.g:
PgSql.Array(1,2,3) //= ARRAY[1,2,3]
var strings = new[]{ "A","B","C" };
PgSql.Array(strings) //= ARRAY['A','B','C']
Which you can safely use in Custom SQL Expressions that use PostgreSQL's native ARRAY support:
q.And($"{PgSql.Array(anyTechnologyIds)} && technology_ids")
q.And($"{PgSql.Array(labelSlugs)} && labels");
If you want and empty collection to return null
instead of an empty ARRAY[]
you can use the nullIfEmpty
overload:
PgSql.Array(new string[0], nullIfEmpty:true) //= null
PgSql.Array(new[]{"A","B","C"}, nullIfEmpty:true) //= ARRAY['A','B','C']