Skip to content

Extension method reference

Bart Read edited this page Jan 20, 2016 · 12 revisions

##Overview

The extension methods are designed to allow you to save changes to a root object, along with any child objects it contains, dependent upon how you've configured your DAOs.

All methods are added to the IDbConnection interface but note that, whilst we support the interface, in reality the only RDBMS supported at present is SQL Server. Dapper.SimpleSave should work with SQL Server 2005 and later, including SQL Server 2016 CTP 3.2.

It's perfectly OK to do partial creates/updates if you have a DAO that represents part of your object hierarchy (or part of a table)

For example, we might define a BasicUserDao that contains only name, email, username, and office phone number details for faster retrieval of only these values via Dapper, and faster saving via Dapper.SimpleSave. Obviously you're on dangerous ground if you try to use one of these 'partial entities' to create new rows because you might be inadvertently violate NOT NULL (or other) constraints. The only warning you'll have of this is when you get an error back from the database, and your save will fail.

Note that, as a general rule, if you need the full DAOhierarchy for some part of handling a request, you should use it throughout. The cost of an additional round trip to the database just to get a more slimline version of the data when you need full fat elsewhere will vastly outweigh any saving made by not building the full hierarchy.

This implies a design decision: if some methods work with a partial DAO, and some with full fat, then you may wish to implement the partial DAO as a base class of the full to take advantage of polymorphism. Of course you may prefer a clean separation with no inheritance, at the cost of some duplication.

##Saving single root objects

The following extension methods can be used to save a single object:

public static void Create<T>(
    this IDbConnection connection,
    T obj,
    IDbTransaction transaction = null);

Create a row for object obj along with rows for its children that need to be INSERTed in the database. Exact behaviour will depend upon how you have decorated DAOs.

public static void Update<T>(
    this IDbConnection connection,
    T oldObject,
    T newObject,
    IDbTransaction transaction = null);

Update the database with any differences between oldObject and newObject, and their children. Exact behaviour will depend upon how you have decorated DAOs.

public static void Delete<T>(
    this IDbConnection connection,
    T obj,
    IDbTransaction transaction = null);

Delete obj along with any child rows that need to be removed. Exact behaviour will depend upon how you have decorated DAOs.

public static void SoftDelete<T>(
    this IDbConnection connection,
    T obj,
    IDbTransaction transaction = null);

Soft delete the row specified by obj. This involves setting or unsetting the value of a boolean (i.e., BIT) column in the row and does not recurse down into child objects in order to avoid losing information should you decide to undelete the row again later on. See description of the [SoftDeleteColumn] attribute for more information.

###Usage

To save an object, all you have to do is call the appropriate method.

When using the Update<T> method, you must supply both the old version of the object and the new version (see How Dapper.SimpleSave works for an explanation).

  • If you only supply the old version you will end up deleting the object.

  • If you supply only the new version, the behaviour differs:

    • with no primary key specified, you'll create a new object in the database,

    • if a primary key value is specified and UPDATE will be executed against all columns represented by properties in your DAO

Note that "cheating" UPDATEs, by executing them only with a new object, may lead to incorrect results in child collections of objects since Dapper.SimpleSave will not be able to tell if any objects have been added or removed.

(Today's challenge: without looking at the code, see if you can figure out how Create and Delete are implemented.)

###Transactions

All SQL commands Dapper.SimpleSave issues will be executed within a transaction. This can be a transaction you create, or otherwise Dapper.SimpleSave will create one for you. See Transactions for more information.

###A brief word on SoftDelete<T>(...)

Use SoftDelete<T>(...) when, rather than actually deleting records, you only want to mark them as deleted by setting a BIT/bool value on a column. You need to mark the property corresponding to this column with the [SoftDeleteColumn] attribute.

When you soft delete only the root record will be marked as soft deleted. Child records in other tables will be untouched. This is because, say you want to undo the soft delete, it becomes possible to restore the entire hierarchy or records. If we recursively soft deleted we'd lose information about any child records that may or may not have been separately soft deleted.

##Saving collections of objects

Use these IDbConnection extension methods to save collections of objects:

public static void CreateAll<T>(
    this IDbConnection connection,
    IEnumerable<T> newObjects,
    IDbTransaction transaction = null);

Create a row for all objects in newObjects along with rows for their children that need to be INSERTed in the database. Exact behaviour will depend upon how you have decorated DAOs. All rows for all objects will be INSERTed or UPDATEd as part of the same transaction.

public static void UpdateAll<T>(
    this IDbConnection connection,
    IEnumerable<Tuple<T, T>> oldAndNewObjects,
    IDbTransaction transaction = null);

Update the database with any differences between oldAndNewObjects, and their children. Each Tuple contains a pair of old and new objects. Exact behaviour will depend upon how you have decorated DAOs. All updates will occur as part of the same transaction.

public static void UpdateAll<T>(
    this IDbConnection connection,
    IEnumerable<T> newObjects,
    Func<T, T> mapNewObjectToOldObject,
    IDbTransaction transaction = null);

Update the database with any differences between newObjects and the old objects they map to in mapNewObjectToOldObject, and their children. Exact behaviour will depend upon how you have decorated DAOs. All updates will occur as part of the same transaction.

public static void UpdateAllMappingFromOldObjects<T>(
    this IDbConnection connection,
    IEnumerable<T> oldObjects,
    Func<T, T> mapOldObjectToNewObject,
    IDbTransaction transaction = null);

Update the database with any differences between oldObjects and the new objects they map to in mapOldObjectToNewObject, and their children. Exact behaviour will depend upon how you have decorated DAOs. All updates will occur as part of the same transaction.

public static void DeleteAll<T>(
    this IDbConnection connection,
    IEnumerable<T> oldObjects,
    IDbTransaction transaction = null);

Delete all objects in oldObjects along with any child rows that need to be removed. Exact behaviour will depend upon how you have decorated DAOs. All DELETEs and UPDATEs will be performed in the same transaction.

public static void SoftDeleteAll<T>(
    this IDbConnection connection,
    IEnumerable<T> objects,
    IDbTransaction transaction = null);

Use SoftDeleteAll<T>(...) when, rather than actually deleting records, you only want to mark them as deleted by setting a BIT/bool value on a column. You need to mark the property corresponding to this column with the [SoftDeleteColumn] attribute.

Similarly SoftDeleteAll<T>(...) will mark all root records in the collection as soft deleted. Remember to add the [SoftDeleteColumn] attribute to the relevant property on your Ts.

For all methods, the same principles, particularly with respect to transactions, apply here as to the single object methods.

Clone this wiki locally