-
Notifications
You must be signed in to change notification settings - Fork 13
Configuring the behaviour of Dapper.SimpleSave with attributes
##Overview
The behaviour of Dapper.SimpleSave is controlled by decorating your DAOs with attribute indicating, for example, which properties represent primary key columns, the cardinality of relationships between tables, the names of database tables and columns (where the latter need to be overridden), etc.
In future we may support alternative configuration mechanisms, such as wire-up, which would mean the types being saved don't need to know anything about Dapper.SimpleSave. If this is particularly of interest to you, please start a discussion, or submit a pull request.
We also don't support convention based saving. Dapper.SimpleSave was initially built to help us work with a database that was too complex for convention over configuration to be really helpful, since there would have been so many exceptions where some level of configuration would be needed. This doesn't mean that we wouldn't consider supporting convention over configuration in future, but it's not there at the moment. Again, if it's of interest to you please consider discussing it on our Google Group, or submit a pull request.
The only exception to this is the [ManyToMany] attribute, which does make some assumptions about how your link tables are structured (see below).
Taking all of the above into account, the real art of using Dapper.SimpleSave effectively comes in knowing how and when to use the different attributes.
##Basic attributes
-
[Table(schemaQualifiedTableName)]- every type you want to save should be decorated with this attribute. We've only tested it on classes, but it ought to work with interfaces (it may not honour the contract at the moment), and structs too. You must qualify the table name with its schema, e.g., "[user].[USER_MST]". We recommend the use of square braces around identifiers to avoid running into potential issues with T-SQL reserved words, of which there are a surprisingly large number. -
[ReferenceData]- add this attribute to any type representing a table that contains reference data that is not intended to be updated. Dapper.SimpleSave will not try to save entities marked as such to the database, unless you use the constructor overload that takes a bool indicating whether or not the table has updateable foreign keys. If so, i.e., you passed in true, it will allow the update of columns containing foreign key values only. You can also add this attribute to properties if you want to treat the property's type as reference data in the context of that property to stop Dapper.SimpleSave from trying to write to it. -
[PrimaryKey]- mark the property used as the primary key, which must be an int?, long?, or GUID? with this attribute. -
[Column(name)]- not needed in most cases but, if your database column name differs from the property name in code, mark it with this attribute and pass in the name of the column in the database. -
[SimpleSaveIgnore]- mark any properties you don't want saved to the database with this. For example, you might want to ignore any computed columns. -
[ReadOnly]- this attribute has been deprecated and replaced by[SimpleSaveIgnore]. If you continue to use the[ReadOnly]attribute you'll get a compile time error that asks you to use[SimpleSaveIgnore]instead. -
[SoftDeleteColumn(trueIndicatesDeleted)]- for situations where you need to support soft deletion of database records, mark the column that indicates whether or not a record is live or deleted with this attribute. Only columns of typeBIT(i.e., mapping toboolin C#) are supported. You can optionally pass a parameter indicating whethertrue(or 1) indicates the record has been deleted, orfalse(i.e., 0, the default).
##Relationship cardinality attributes
-
[ManyToMany(schemaQualifiedLinkTableName)]- mark enumerable properties with a many to many relationship with the underlying entity with this. Dapper.SimpleSave will not try to update the underlying entity at all, but rather will add or remove records in the specified link table. In a many to many relationship Dapper.SimpleSave will assume that child records should not be modified since other records in the parent table may depend on them. If you need to update items in the enumerable you should define a different DTO type for this purpose. -
[ManyToOne]- mark any properties representing many to one relationships with this attribute. Dapper.SimpleSave will assume the foreign key is in the column corresponding to the marked property. It's fine to use the [Column] attribute to specify a different name for the underlying column if it doesn't match the property name. Again, since other records can depend upon the child object, Dapper.SimpleSave will not try to modify child rows. If you need to modify the child rows define another DTO type for this purpose. -
[OneToMany]- mark any properties representing one to many relationships with this attribute. Dapper.SimpleSave will look for the foreign key in the child object. -
[OneToOne]- one to one relationships can be defined with the foreign key either on the parent or the child. Therefore, if the property is also marked with a[ForeignKey](see below), Dapper.SimpleSave will assume there is an underlying column containing the foreign key value (again, renaming with[Column]is fine) in the parent entity. Otherwise it will assume the foreign key is in the child entity and you should supply the name of the FK column to the constructor for[OneToOne], and mark the appropriate property on the child type with a[ForeignKey]attribute. -
[ForeignKey(Type referencedDto)]- in practice, rarely needed. Marks a property as a foreign key relationship with the specified DTO. Generally only needed for one to one relationships.
##Example
We've talked elsewhere about the concept of a user in an organisation, with the following properties:
- A User:
- has one Office Phone Number,
- has one Position
- is a member of one or more Departments,
- and one or more Teams,
- and has zero or more Additional Roles,
- as well as a bunch of basic properties like FirstName, LastName, Username, Email, etc.
Here's what a DAO for our user type might look like after we've decorated it with Dapper.SimpleSave attributes:
[Table("[user].USER_MST")]
public class UserDao
{
[PrimaryKey]
public int? UserKey { get; set; }
public Guid UserGUID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string PasswordSalt { get; set; }
[Column("UserStatusKey")]
[ManyToOne]
public UserStatusEnum Status { get; set; }
public string CountryCode { get; set; }
public string PersonalMobileNumber { get; set; }
public string BusinessMobileNumber { get; set; }
[Column("OfficeNumberKey")]
[OneToOne]
[ForeignKeyReference(typeof(OfficeNumberDao))]
public OfficeNumberDao OfficeNumber { get; set; }
public string VirtualLineNumber { get; set; }
public string EmailAddress { get; set; }
public int PasswordFailureCount { get; set; }
[ManyToOne]
[Column("PositionKey")]
public PositionDao Position { get; set; }
[ManyToMany("[user].USER_DEPARTMENT_LNK")]
public IList<DepartmentDao> Department { get; set; }
[ManyToMany("[user].USER_ADDITIONAL_ROLES_LNK")]
public IList<RoleDao> AdditionalRoles { get; set; }
[ManyToMany("[user].USER_TEAM_LNK")]
public IList<TeamDao> Team { get; set; }
}