DataObjects.Net includes a set of rules for defining the default value for a persistent property.
The rules are the following:
Let T is the type of a persistent property, then:
1. T is a primitive type
If T is a primitive type, Guid or String then the default value for the property is default(T) and the type of the underlying column is T.public class Animal : Entity { ... [Field] public int Age { get; set; } CREATE TABLE Animal ( ... [Age] [int] NOT NULL
2. T is Nullable<>
If T is Nullable<> then the default value is NULL and the type of the underlying column is Nullable T.public class Animal : Entity { ... [Field] public int? Legs { get; set; } CREATE TABLE Animal ( ... [Legs] [int] NULL
3. T is a reference type
If T is a reference type then the default value is NULL and the type of the underlying column is the type of primary key of the referenced Entity.public class Animal : Entity { ... [Field] public Person Owner { get; set; } CREATE TABLE Animal ( ... [Owner.Id] [int] NULL
These rules are more or less obvious and straightforward but what if the overwhelming majority of animals in your application universe have 4 legs and you don't want to set this property manually again and again? Or there should not be homeless animals? Then I guess, you should have the opportunity to override these rules.
This can be done with the help of [Field] attribute.
1. Setting default value for a primitive persistent property
public class Animal : Entity { ... [Field(DefaultValue = 4)] public int? Legs { get; set; } CREATE TABLE Animal ( ... [Legs] [int] NULL ... ALTER TABLE [dbo].[Animal] ADD CONSTRAINT [DF_Animal_Legs] DEFAULT ((4)) FOR [Legs]
2. Changing nullability of a reference field.
public class Animal : Entity { ... [Field(Nullable = false)] public Person Owner { get; set; } CREATE TABLE Animal ( ... [Owner.Id] [int] NOT NULLThis setting leads to NOT NULL column which means that the value of the property must be set prior to any Session.Persist() call while constructing the Animal entity. Therefore, the right way to set such properties is inside entity's constructor, before executing any queries.
3. Setting default value for a reference persistent property.
Note, this feature is implemented in the upcoming version of DataObjects.Net (by upcoming I mean 4.3.8 or 4.4.1 branches).public class Animal : Entity { ... [Field(DefaultValue = 1)] // 1 here is the key of the default animal owner public Person Owner { get; set; } CREATE TABLE Animal ( ... [Owner.Id] [int] NULL ... ALTER TABLE [dbo].[Animal] ADD CONSTRAINT [DF_Animal_OwnerId] DEFAULT ((1)) FOR [Owner.Id]This makes sense in a scenario when the key of the default referenced entity is already known on a compilation step or it is a well-known constant identifier so there is an Entity with that key in the domain.
I hope these little tricks will help you in modelling your domains with even less efforts.
Nice!
ReplyDeleteI also saw an example of Field(DefaultValue..) that uses enum http://support.x-tensive.com/question/4559/default-field-set-to-enum-works-for-memory-database-but-not-postgres
Good work!
Right.
ReplyDeleteMalisa, thanks for pointing to that. I'll update the post.