Sorry if this has been answered, but I didnt get any hits on stackoverflow or this forum. I am looking at a system where I need to implement soft deletes. In the past, in dapper, i wrote some extension crud methods to cater for this (e.g. if Table Implements ISoftDeleteable, by default select only where RecordState = ACTIVE). This “works” , but you still end up writing a lot of code to explicitly handle the softdelete states in various places as more complex queries are required.
Is there any support or recommended pattern for soft deletion when using ServiceStack.ormlite? I have seen (and once, implemented) this logic in EntityFramework, whereby logic would (behind the scenes) append filters to queries to limit out the deleted items, but I havent come across anyone using this same idea in SS?
OrmLite doesn’t include any notion of Soft deletes and there’s no filter you can use to you modify every SELECT query performed.
I’d probably do something like add an extension method to SqlExpression<T> which appends the condition to an SqlExpression, e.g:
public static class SqlExpressionExtensions
{
public static SqlExpression<T> OnlyActive<T>(this SqlExpression<T> q)
where T : ISoftDelete
{
return q.Where(x => x.IsDeleted != true);
}
}
Then just stick to APIs that accept an SqlExpression which you can use to chain it at the end, e.g:
var results = db.Select(db.From<Table>().OnlyActive());
var result = db.Single(db.From<Table>().Where(x => x.Name == "foo").OnlyActive());
You’ll need to specify it for each table that you want to add this filter to, but then it will be executed for each SqlExpression query so you don’t need to add it via an extension method, e.g:
var results = db.Select(db.From<Table>());
var result = db.Single(db.From<Table>().Where(x => x.Name == "foo"));
This also applies to APIs which take a lambda expression since they use an SqlExpression<T> under the hood, e.g:
var result = db.Single(x => x.Name == "foo");
I’ve also added a generic delegate that applies to all SqlExpressions, but you’ll get access to a IUntypedSqlExpression instead of a SqlExpression<T> but it lets you execute a custom filter for all SqlExpression<T> which you can use to add a filter for all tables implementing ISoftDelete, e.g:
This works as above where it will apply the filter to all SqlExpression based queries, e.g:
var results = db.Select(db.From<Table>());
var result = db.Single(db.From<Table>().Where(x => x.Name == "foo"));
var result = db.Single(x => x.Name == "foo");
That’s because the SqlExpressionSelectFilter only applies when you’re using an SqlExpression and OrmLite doesn’t use the overhead of a Typed SqlExpression unless it has to, e.g. it has an expression it needs to query.
API’s that need to filter using a Typed Expression like:
"ToDo with Order 1: {0}".Print(db.Select<Todo>(td => td.Id == 1).Dump());
Will use a SqlExpression behind the scenes, but if there’s no filter it most cases wont, you can force one by passing in the SqlExpression in the Query, e.g:
The unit test for filtering joined tables doesn’t look like it will properly test the join because the main table being selected from has IsDeleted true. It appears to me that the filter is not actually applied on joined tables, only on the main table.
If you change the ModelWithSoftDelete to not be deleted, and leave the ModelWithSoftDeleteJoin as deleted, the expected result for the select should still be null, but the test fails.