AdFactum ObjectMapper .NET Blog

Official blog of the AdFactum ObjectMapper .NET

Archive for the 'Attributes' Category

Attribute: [Unicode]

Posted by Gerhard Stephan on 7th March 2008

For all databases that supports Unicode (e.g. Oracle and Microsoft SQL Server),  a string property can be tagged with the [Unicode] attribute. The AdFactum ObjectMapper .NET does therefore use the Unicode Data Types for the specific property.

Below you’ll find all supported datatypes that can be used with the Unicode attribute.

    public class UnicodeTestEntity : ValueObject

    {

        private char unicodeChar;

        private string unicodeString;

        private string unicodeMemo;

 

        /// <summary>

        /// Gets or sets the unicode char.

        /// </summary>

        /// <value>The unicode char.</value>

        [Unicode]

        public char UnicodeChar

        {

            get { return unicodeChar; }

            set { unicodeChar = value; }

        }

 

        /// <summary>

        /// Gets or sets the unicode string.

        /// </summary>

        /// <value>The unicode string.</value>

        [Unicode]

        [PropertyLength(30)]

        public string UnicodeString

        {

            get { return unicodeString; }

            set { unicodeString = value; }

        }

 

        /// <summary>

        /// Gets or sets the unicode memo.

        /// </summary>

        /// <value>The unicode memo.</value>

        [Unicode]

        [PropertyLength(int.MaxValue)]

        public string UnicodeMemo

        {

            get { return unicodeMemo; }

            set { unicodeMemo = value; }

        }

    }

 

 

Posted in Attributes | No Comments »

Attribute: [GroupBy]

Posted by Gerhard Stephan on 7th March 2008

The [GroupBy] attribute can be used to group properties by there value. This property can only be used in projection classes.

    /// <summary>

    /// Groups the time entries by their project id

    /// </summary>

    public class TimeEntryGrouping

    {

        private DateTime minDate;

        private string project;

 

        /// <summary>

        /// Gets or sets the min date.

        /// </summary>

        /// <value>The first date.</value>

        [ProjectOntoProperty(typeof(TimeEntry), "StartDate")]

        [Min]

        public DateTime MinDate

        {

            get { return minDate; }

            set { minDate = value; }

        }

 

        /// <summary>

        /// Gets or sets the project.

        /// </summary>

        /// <value>The project.</value>

        [ProjectOntoProperty(typeof(TimeEntry), "ProjectId")]

        [GroupBy]

        public string Project

        {

            get { return project; }

            set { project = value;  }

        }

    }

 

Select the grouping:

 

                List<TimeEntryGrouping> result =

                    new List<TimeEntryGrouping>(

                        new ListAdapter<TimeEntryGrouping>(

                    mapper.FlatSelect(typeof(TimeEntryGrouping))));

 

Posted in Attributes | No Comments »

Attribute: [Avg], [Count], [First], [Last], [Max], [Min] and [Sum]

Posted by Gerhard Stephan on 7th March 2008

This aggregation attributes can be placed on any projection property of a projection class.

    public class TimeEntryAggregation

    {

        private DateTime minDate;

 

        /// <summary>

        /// Gets or sets the min date.

        /// </summary>

        /// <value>The first date.</value>

        [ProjectOntoProperty(typeof(TimeEntry), "StartDate")]

        [Min]

        public DateTime MinDate

        {

            get { return minDate; }

            set { minDate = value; }

        }

    }

    var minTimeEntry = mapper.Load(typeof(TimeEntryAggregation), null as ICondition) as TimeEntryAggregation;

 
The following attributes can be used this way:

  • [Avg] 
  • [Count]
  • [First], [Last]
  • [Min], [Max]
  • [Sum]

Posted in Attributes | No Comments »

Attribute: [View]

Posted by Gerhard Stephan on 18th January 2008

This attribute can be used to define that a class is mapped to a database view.

      [View („VW_CONTACTS“)]

      public class Contact : ValueObject

 

The attribute is important for the Persisters, because some selects will fired in a different way, if you query a database view. If you want to map a database table, you can use the attribute called "Table".

Posted in Attributes | No Comments »

Attribute: [ProjectOntoProperty]

Posted by Gerhard Stephan on 12th November 2007

The attribute [ProjectOntoProperty] is used to build projections of distinct source tables.

Defintion:

  1. A projection is a result subset of the queried tables.
  2. A projection can be used as a query result, instead of quering an IValueObject type.

That implicates, that a projection class (that uses the ProjectOntoProperty) must not implement the IValueObject interface.

Example:

Imagine you would have two value object types: A Company with their employees. Now you wanto to query the employees. As an additional information you want to output the name of the company where the employees are working. Because of this, you would have a a result type that is compound of the type company and employee.

List<FullFeaturedEmployee> names = new List<FullFeaturedEmployee>(

      new ListAdapter<FullFeaturedEmployee>(

            mapper.Select(

                  typeof(FullFeaturedEmployee),

                  new CollectionJoin(

                        typeof(Company),

                        "Employees",

                        typeof(Employee)

                  )

            )));

 

    /// <summary>

    /// Projects results of the company legalname and the employee names

    /// </summary>

    public class FullFeaturedEmployee

    {

        private int companyId;

        private int employeeId;

 

        private string companyName;

        private string firstName;

        private string lastName;

 

        [ProjectOntoProperty(typeof(Company), "LegalName")]

        public string CompanyName

        {

            get { return companyName; }

            set { companyName = value; }

        }

 

        [ProjectOntoProperty(typeof(Employee), "FirstName")]

        public string FirstName

        {

            get { return firstName; }

            set { firstName = value; }

        }

 

        [ProjectOntoProperty(typeof(Employee), "LastName")]

        public string LastName

        {

            get { return lastName; }

            set { lastName = value; }

        }

 

        [ProjectOntoProperty(typeof(Company), "Id")]

        public int CompanyId

        {

            get { return companyId; }

            set { companyId = value; }

        }

 

        [ProjectOntoProperty(typeof(Employee), "Id")]

        public int EmployeeId

        {

            get { return employeeId; }

            set { employeeId = value; }

        }

    }

 

Important:

A projection class (that uses the ProjectOntoProperty) must not implement the IValueObject interface.

Posted in Attributes | No Comments »

Attribute: [DefaultValue]

Posted by Gerhard Stephan on 13th July 2007

The attribute [DefaultValue] can be used to specify a default value for a property. The [DefaultValue] attribute only affects the creation of the DDL file where a DEFAULT value is added to the field definition of the database.

        [PropertyLength(100)]

        [DefaultValue("Unkown Company")]

        public string LegalName

        {

            get { return legalName; }

            set { legalName = value; }

        }

The resulting field definition would be:

	LegalName VARCHAR(100) DEFAULT 'Unkown Company';

Posted in Attributes | No Comments »

Attribute: [GeneralLink]

Posted by Gerhard Stephan on 11th June 2007

The attribute [GeneralLink] is the opposite of the attribute [BindPropertyTo]. It binds a property to a general class with an unspecified type. Therefore the type name of the bind object will be stored in an additional column. The name of that type column is calculated by the column name of the bound property added with a "#TYP".

        /// <summary>

        /// Gets or sets the contacts.

        /// </summary>

        /// <value>The contacts.</value>

        [GeneralLink(typeof(Contact))]

        public IList Contacts

        {

            get { return contacts; }

            set { contacts = value; }

        }

All objects that are stored within that collection, must be derived of the class "Contact" or must be objects of that type.

        /// <summary>

        /// Gets or sets the person.

        /// </summary>

        /// <value>The person.</value>

        [GeneralLink(typeof(IPerson))]

        public IPerson Person

        {

            get { return person; }

            set { person = value; }

        }

 

All objects that are stored in property "Person", must implement the interface "IPerson".

        /// <summary>

        /// Gets or sets the contacts.

        /// </summary>

        /// <value>The contacts.</value>

        [GeneralLink]

        public IList Contacts

        {

            get { return contacts; }

            set { contacts = value; }

        }

 

        /// <summary>

        /// Gets or sets the person.

        /// </summary>

        /// <value>The person.</value>

        [GeneralLink]

        public IPerson Person

        {

            get { return person; }

            set { person = value; }

        }

Note: If no base class has been specified, "ValueObject" will be taken as the base type for the linked objects. Therefore all objects that will be stored within that collection must be derived from the class "ValueObject".

Additionally have a look at the blog entry "How to do bind collections"

Posted in Attributes | No Comments »

Attribute: [PrimaryKey]

Posted by Gerhard Stephan on 11th June 2007

The property PrimaryKey can be used to tag a property that acts as a primary key column for the mapped table. In our classes ValueObject and AutoIncValueObject the Id Property has this attribute already assigned. Therefore this is only important if you write your own base classes or you define interfaces that shall be mapped.

    /// <summary>

    /// Interface that describes a person

    /// </summary>

    public interface IPerson : IValueObject

    {

        /// <summary>

        /// Gets or sets the unique value object id.

        /// </summary>

        /// <value>The unique value object id.</value>

        [PrimaryKey]

        new int? Id

        {

            get;

            set;

        }

 

 

Note: Combined primary keys are not allowed using the AdFactum ObjectMapper .NET.

Hint: It’s also valid to tag the primary key property with additional attributes, like [PropertyName] or [PropertyLength] to change the database binding.

Posted in Attributes | 1 Comment »

Attribute: [VirtualLink]

Posted by Gerhard Stephan on 7th May 2007

The Virtual Link functionality is the most powerful feature the AdFactum ObjectMapper .NET offers.

What are Virtual Links?

Using Virtual Links you can implement objects that acts like database views. This enables you to join directly the values of your foreign key tables to your business entity.

What is the advantage?

The advantage is, that you don’t need to re-load Foreign Key Tables in order to get the display value of a foreign key. This saves you one SQL re-load per foreign key, and this without any further overhead.

If you are using the translation functionality of the AdFactum ObjectMapper .NET, the display values are already translated into your favoured language.

How can I use Virtual Links?

You can tag properties of your class with the [VirtualLink] attribute. Properties that are tagged with that attribute are only relevant when loading the entity. But they will be ignored when storing the entity to database.

        /// <summary>

        /// Department Key

        /// </summary>

        [PropertyName("DEPARTMENT")]

        [PropertyLength(4)]

        public string DepartmentKey

        {

            get { return departmentKey; }

            set { departmentKey = value; }

        }

 

        /// <summary>

        /// Department Text

        /// </summary>

        [VirtualLink(typeof(DepartmentText), "Value", "Key", "DepartmentKey")]

        public string DepartmentText

        {

            get { return departmentText; }

            set { departmentText = value; }

        }

 

In this example the Virtual Link would join the property "Key" of the class "DepartmentText" with the property "DepartmentKey" of the current class. As a result the property "DepartmentText" would be filled with the property "Value". And that represents the display value of the foreign key "DepartmentKey".

Because the VirtualLink represents a foreign key constraint, you don’t have to use the [ForeignKey] attribute on top of the property "Department Key". It would be a duplicate information.

And the best. It’s all working in background. You only have to load your business entity as usual.

How can I use Virtual Links for translation?

Imagine the property "DepartmentText" would be a translated value. E.g. different department descriptions for german and english. In that case you need to add a translation parameter which you can set when loading the business entity.

        public const string LOCALE_PARAMETER = "@LOCALE";

 

        /// <summary>

        /// Department Text

        /// </summary>

        [VirtualLink(typeof(DepartmentText), "Value", "Key", "DepartmentKey", "Locale", LOCALE_PARAMETER)]

        public string DepartmentText

        {

            get { return departmentText; }

            set { departmentText = value; }

        }

 

The property "Locale" of the class "DepartmentText" would hold the localization value, eg. "de-DE" or "en-GB". When loading the business entity, it’s necessary to set the global parameter in order to set the language for the virtual link.

     Hashtable globalParameter = new Hashtable();

     globalParameter[LOCALE_PARAMETER] = "de-DE"; // or another value like "en-GB"

 

     Company company = mapper.FlatLoad(typeof (Company), companyId, globalParameter) as Company;

 

The method "Load" of the AdFactum ObjectMapper .NET joins the global parameters, specified by the given hashtable, with the virtual links that are specified by the company business entity. The whole class DepartmentText would be implemented like:

    public class DepartmentText : ValueObject

    {

        public const int KEY_UNIQUE_GROUP = 1;

        public const int VALUE_UNIQUE_GROUP = 2;

 

        private string valueText;

        private string key;

        private string locale;

 

        [PropertyLength(4)]

        [Unique(KEY_UNIQUE_GROUP)]

        [Required]

        public string Key

        {

            get { return key; }

            set { key = value; }

        }

 

        [PropertyLength(512)]

        [Unique(VALUE_UNIQUE_GROUP)]

        public string Value

        {

            get { return valueText; }

            set { valueText = value; }

        }

 

        /// <summary>

        /// Language setting in standard .NET (e.g. en-US ; de-DE)

        /// </summary>

        [PropertyLength(5)]

        [Required]

        [Unique(KEY_UNIQUE_GROUP)]

        [Unique(VALUE_UNIQUE_GROUP)]

        public string Locale

        {

            get { return locale

            set { locale = value; }

        }

    }

 

What is the pitfall?

Like everything Virtual Links have their pitfalls too. If a class contains a lot of Virtual Links it can slowdown your database query. It depends on your database, your tables and the data within the tables to define how many virtual links are necessary to slowdown your query. Out of my experience I would say about 10 virtual links in one class is the limit. If you need more virtual links, I would load them in a second step after loading the plain object. In that case, you have to tag such empty properties with the attribute [Ignore]. If you have less than 10 virtual links within a class file, the Virtual Link functionality speed up your database query logic and saves you a lot of implementation work.

Conclusion: Virtual Links can be used for a very wide range of use cases. And it can save you a lot of coding time if you use them properly. 

Posted in Attributes | No Comments »

Attribute: [ForeignKey]

Posted by Gerhard Stephan on 19th April 2007

Beside the automatic generation of foreign keys, it’s sometimes necessary to create foreign keys that are driven by business logic. Those foreign keys can’t be handled automatically, but they have to be set manually with the ForeignKey attribute.

Create a single foreign key relation:

Creating a single foreign key relation is pretty easy. This can be done by attributing the property with the ForeignKey attribute:

        [ForeignKey(typeof(RangeText), "Key")]

        public new string FilterKey

        {

            get { return base.FilterKey; }

            set { base.FilterKey = value; }

        }

 

The resulting DDL script would look like:

alter table RANGE

  add constraint RANGE_FK01 foreign key (FILTERKEY)

  references RANGETEXT (KEY);

Create compound foreign keys using key groups:

In order to create compound foreign keys you have to bundle the affected properties in foreign key groups. A foreign key group owns a number that identifies the group. The number itself isn’t significant, it’s only important that the properties you want to group have the same key group number assigned.

        [ForeignKey(UNIQUE_GROUP, typeof(ManufactoryText), "Key")]

        public new string FilterKey

        {

            get { return base.FilterKey; }

            set { base.FilterKey = value; }

        }

 

        [ForeignKey(UNIQUE_GROUP, typeof(ManufactoryText), "Locale")]

        public new string Locale

        {

            get { return base.Locale; }

            set { base.Locale = value; }

        }

 

The resulting DDL script would look like:

 

alter table MANUFACTORY

  add constraint MANUFACTORY_FK01 foreign key (FILTERKEY, LOCALE)

  references MANUFACTORYTEXT (KEY, LOCALE);

Create compound foreign keys using key groups with sorted keys:

Additional to the foreign key group feature you can sort the keys within the foreign key group. Have a look at the example above. Most times it is necessary to store the properties in a defined sorting. That’s important if you have an compound index on the table you want to use with the compound foreign key.

In that case, the second number, after the foreign key group defines the sorting of the keys. Imagine you want to change the ordering of the keys in our example above.

        [ForeignKey(UNIQUE_GROUP, 2, typeof(ManufactoryText), "Key")]

        public new string FilterKey

        {

            get { return base.FilterKey; }

            set { base.FilterKey = value; }

        }

 

        [ForeignKey(UNIQUE_GROUP, 1, typeof(ManufactoryText), "Locale")]

        public new string Locale

        {

            get { return base.Locale; }

            set { base.Locale = value; }

        }

 

The resulting DDL Script would look like: 

alter table MANUFACTORY

  add constraint MANUFACTORY_FK01 foreign key (LOCALE, FILTERKEY)

  references MANUFACTORYTEXT (LOCALE, KEY);

 

As you can see the sorting of the columns within the foreign key group changed.

Summary:

The foreign key attribute offers you a lot of possibilities to cover more than 90% of all use cases for that you might need foreign key constraints. The last 10% should be better left to a seasoned database admin, because they are such special that they can’t be handled by a generic OR Mapping tool.

Cheers
Gerhard

Posted in Attributes | No Comments »