Mindscape
  • Register
  • Login
  • YOUR CART IS EMPTY
home
Software
  • Developers Toolbox
  • LightSpeed
  • Raygun
  • WPF Elements
  • Web Workbench
  • Metro Elements
  • Silverlight Elements
  • NHibernate Designer
  • Phone Elements
  • WPF Diagrams
  • Simple DB management
  • Visual Tools for SharePoint
Downloads
Store
  • Buy online
  • Purchase order
  • Volume discounts
  • Reseller
  • Software license
  • Contact sales
Blog
Support
About
  • About Us
  • Contact
  • Testimonials
rss
twitter
facebook
Domain Modelling Techniques Inheritance Value Objects Reference Data and Lookups

Value Objects

Many attributes of an entity can be represented by primitive values such as integers or strings.  However, it’s sometimes useful to represent an attribute by a type with more specific meaning.  Such an attribute might be a single column, for example representing a Salary column by a Money type instead of Decimal, or it might be multiple columns, for example representing LocationX and LocationY columns by a Point or Position type instead of a two separate Doubles.

In these examples, Money, Point and Position are value objects.  They are not entities, because they do not have identity of their own: they are just a way of representing entity attributes in a more business-meaningful way.  Value objects are idiomatic in domain-driven design and are discussed in detail in Eric Evans’ book of the same name.

Defining a Value Object Type in the Designer

To define a value object type in the designer, drag a Value Object icon from the Toolbox into the model.  You can name the type and add properties just as you do with entities.

Notice that a value object type does not have a base class or identity type, because a value object represents an attribute of an entity, and does not have identity in itself.

Creating a Value Object Member in the Designer

Once you have defined a value object type, you can create an entity property of that type by choosing the Value Object Property connector from the Toolbox and dragging a line from the entity to the value object type.  You can edit the name of the property through the line label or the Name property.

Value Objects in Database-First Development

Relational databases don’t have a concept of value objects, so when you drag a table onto the designer, LightSpeed can’t automatically infer value objects from the table schema.

After dragging the table on, however, you may identify a set of columns which you want to represent as a value object member.  If these columns’ names have a common prefix (see Value Object Database Mappings below) then you can extract them to a value object by selecting the columns, right-clicking the multiple selection and choosing Extract to Value Object.  Depending on whether a value object type suitable for mapping these columns is already defined, the designer will offer to map the columns to an existing value object type, to add the columns to an existing value object type, or to create a new value object type (and a member of that type).

Defining a Value Object Type in Code

At the code level, a value object type is just an ordinary CLR type – class or struct.  As with entities, LightSpeed is interested in the fields of the type, not the properties: therefore, you must not use automatic properties (because the backing field for an anonymous property does not have the ‘right’ name for LightSpeed to map it).

Value object types should be immutable.  All fields should be read-only, and the wrapper properties should be get‑only.

A simple value object type

public class Money
{
  private readonly decimal _amount; // Fields should be read-only
  public Money(decimal amount)
  {
    _amount = amount;
  }
  public decimal Amount
  {
    get { return _amount; } // Do not use automatic properties
  }
}

Creating a Value Object Member in Code

Fields of value object type are defined in the same way as fields of primitive types, except that you must apply ValueObjectAttribute to the field.

A member of Money type

public class Employee
{
  [ValueObject]
  private Money _salary;
  public Money Salary
  {
    get { return _salary; }
    set { Set(ref _salary, value); }
  }
}

Setting Value Object Properties

Value objects are immutable.  This means you cannot modify the properties of the value object directly.

employee.Salary.Amount = 50000; // Compiler error – Amount property is read-only

The reason for this is that value objects represent values.  Suppose you have an Employee entity with a Salary of $50000.  If the Employee gets a raise, then their Salary changes to a new value of $60000.  It would be wrong to think that $50000 has mutated into $60000.  $60000 is a different value from $50000, so it must be a different instance.  (Remember, value objects don’t have identity.)

Even if you created a mutable value object, you could not set properties this way, because value objects don’t have access to the Entity.Set method which is essential for notifying LightSpeed of changes needing saving – not to mention for UI interfaces such as IEditableObject and INotifyPropertyChanged.

So when you set a value object property, you must always set it to a new instance of the value type.

Setting value object properties

employee.Salary = new Money(50000);
hq.Location = new Position(-41.289, 174.777);

A consequence of this is that when using data binding or data grids you must provide a way to edit your custom value types.  In the Location example, the entity has a single Location, which will appear as a single column in a data grid.  That column will need to display and allow editing of the Position value, but the editor will need to keep producing new Position objects.  You cannot, for example, provide two text boxes, one bound to Location.X and one bound to Location.Y.

Value Object Database Mappings

By default, value object column names are prefixed with the name of the value object field on the containing class.

For example, suppose we have a Site entity with a Location property of type Position, and that Position has the properties X and Y.  Then these would be mapped to columns named LocationX and LocationY in the Site database table.

You can map the column name suffixes associated with the fields in the value object in the same way as you map entity column names: by setting the Column Name option in the designer, or by applying ColumnAttribute in code.

For example, suppose that Position.X were mapped to Longitude and Position.Y to Latitude.  Then the Site Location property would be mapped to the LocationLongitude and LocationLatitude columns in the database.

You can map the column name prefix associated with an occurrence of a value object by setting Column Name Prefix on the connector in the designer, or by applying ColumnAttribute to the value object reference in code.

For example, suppose that Site.Location were mapped to the Coordinates prefix.  Then LightSpeed would map this to CoordinatesX and CoordinatesY columns in the database.

The following table shows how modifiers on a field in a value object (such as Position.X) and modifiers on an occurrence of a value object (such as Site.Location) affect the column name mapping.

Position.X

Site.Location

No modifier

Prefix “Coordinates”

No modifier

LocationX

CoordinatesX

Column “Latitude”

LocationLatitude

CoordinatesLatitude

In legacy databases, the columns of a value object may not share a common prefix, or there may not be a consistent set of suffixes across different sets of columns that you’d like to map to the same value object type.  In this case, you can map individual fields of the value object at the occurrence level using ValueObjectColumnAttribute.  At the time of writing, this is not supported in the designer and can only be used on hand-coded members.

Mapping value object columns to an irregular database schema

public class Site : Entity<int>
{
  [ValueObjectColumn("X", "XPos")]
  [ValueObjectColumn("Y", "YPos")]
  private Position _location;
  [ValueObjectColumn("X", "Easting")]
  [ValueObjectColumn("Y", "Northing")]
  private Position _surveyCoordinates;
}

Data Products

  • LightSpeed ORM
  • NHibernate Designer
  • SimpleDB Tools
  • SharePoint Tools

DevOp Tools

  • Raygun

Visual Controls

  • WPF Elements
  • WPF Diagrams
  • Silverlight Elements
  • Phone Elements

Popular Products

  • Web Workbench

    Modern web development for Visual Studio!

  • Mindscape Megapack

    All Mindscape products for one awesome price!

Quick Links

  • Forums
  • Blog
  • Register
  • Login
  • Contact us
  • Twitter
  • Facebook
  • Google+
  • YouTube
  • Linkedin
  • Rss

© Mindscape 2025. Mindscape is a registered trademark of Mindscape Limited.

  • Terms
  • Privacy