Each table should be mapped to exactly one class. Attributes are used to specify the way classes are mapped to tables. CoolStorage was designed in such a way that mapping objects by hand requires very little typing. As long as the fields in your table have the same name as your class properties, you don't have to add any attributes.
Mapped object classes are declared like this:
[optional attributes] [MapTo("TABLENAME","CONTEXTNAME")] public abstract partial class CLASSNAME : CSObject<CLASSNAME, PRIMARYKEYTYPE> { [optional attributes] public abstract TYPE FIELDNAME1 { get; } [optional attributes] public abstract TYPE FIELDNAME2 { get; set; } [optional attributes] public abstract TYPE FIELDNAME3 { get; set; } [MapTo("COLUMNAME4")] [optional attributes] public abstract TYPE FIELDNAME4 { get; set; } [OneToMany(...)] public abstract CSList<RELATEDCLASS1> FIELDNAME5 { get; } [ManyToOne(...)] public abstract RELATEDCLASS2 FIELDNAME6 { get; set; } }
The only required attribute is the MapTo() attribute on the class itself. The MapTo() attribute tells CoolStorage what table this class should be mapped to, optionally providing a context name if you have more than one database.
(note: for MonoTouch, declarations are a little different: see the MonoTouch page for more information)
All fields that are mapped should be defined as a public abstract property (called a field property), like this:
public abstract TYPE FIELDNAME { get; set; } // set is optional (for read-only fields)
The type of the property should be convertible to the data type of the mapped field. This includes enum types (you can define a property of enum type and map it to a numeric field in the database). When the name of the property is the same as the name of the field, a [MapTo] attribute is not required.
Nullable types are fully supported. If a NULL value is read from the database, and the field property is defined as a nullable type, the value of the property will be NULL. If the type of the property is not nullable, and a NULL value is read from the database, CoolStorage will store the default value for the data type (i.e. zero for integer fields), or a user-defined value (configured via the [NullValue] attribute). You can still determine if the value was NULL by calling the IsNull() method on the object.
Field properties can have the following attributes:
| [MapTo(fieldName)] | Maps the field to the specified field name in the database | |
| [Trim] | Trims spaces from the field after reading from the database. This is useful for fixed length fields of type CHAR, which are always padded with spaces. | |
| [NullValue(value)] | When the data type of the field property is not nullable, and the field in the database is NULL, the field property will be set to the given value. For example, if you have a nullable field in the database, but you map it to a non-nullable Int32, you can specify the attribute [NullValue(1)] for the field property. In that case, when a NULL value is read, the field property value will be set to 1 | |
| [DefaultSort] | You can only have one field property with this attribute. When you read a list of persisted objects (CSList<>), the list will be sorted according to the field which has the [DefaultSort] attribute | |
| [Lazy] | This attribute marks a field as lazy, meaning that it will only be read from the database when first accessed. This is useful for fields which contain a lot of data (blobs or large text fields), but are only accessed in specific cases | |
| [ToString] | Only one field can have the [ToString] attribute, and should only be used on string properties. When the object's ToString() method is called, the contents of this property will be returned | |
Relations between objects (tables/classes) should be defined in the class definitions. There are 4 types of relations between classes:
One-to-One relations are supported, but they are essentially the same as Many-to-One relations, so you should treat One-to-One relations as Many-to-One relations.
A relation field should be defined as a public abstract property, just like a regular field property. One of the relation attributes has to be added to the property declaration (explained below). The type of the property should be the type of the related object for ManyToOne relations, and CSList<objecttype> for the *-to-Many relations.
In cases where the database is designed in such a way that the foreign keys have the same name as local keys, you shouldn't specify which local and foreign keys to use. CoolStorage will figure out the correct relation mapping.
A many-to-one relation should be declared with the [ManyToOne] attribute, optionally specifying the local and foreign keys using the named parameters LocalKey and ForeignKey.
Example:
public abstract class Order : CSObject<Order, int> { //... Fields ... [ManyToOne] public abstract Customer Customer { get; set; } [ManyToOne(LocalKey="SalesPersonID", ForeignKey="EmployeeID") public abstract Employee SalesPerson { get; set; } }
By default, many-to-one relations are "lazy-loaded", meaning the related object will be read when it is first accessed. You can override this behavior by specifying the [Prefetch] attribute on the property. This will make sure CoolStorage reads the related record together with the parent record in one query. In cases where you (almost) always read the related record, this can result in better performance (fewer database round-trips).
One-to-many relations are declared using the [OneToMany] attribute, optionally specifying the local and foreign keys using the named parameters LocalKey and ForeignKey. The data type of the property should be CSList<>. The generic parameter type should be the related class. Only the get property should be declared. The set property is not supported.
Example (showing the reverse relation mappings of the previous example):
public abstract class Customer : CSObject<Customer, int> { // Fields [OneToMany] public abstract CSList<Order> Orders { get; } } public abstract class Employee : CSObject<Employee, int> { // Fields [OneToMany(LocalKey="EmployeeID", ForeignKey="SalesPersonID")] public abstract CSList<Order> SoldOrders { get; } }