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
Creating Domain Models Objects and Databases Creating Models with the Visual Designer Creating Models in Code Creating Modifying and Deleting Entities LightSpeed Configuration Basics Validation Querying the Database Using LINQ Querying the Database Using Query Objects Transactions Working with Entities

Creating Models in Code

The visual designer is an extremely convenient way to create domain models, and most LightSpeed developers use it for almost all modelling requirements.  You can also build a LightSpeed model in code.  Even if you use the designer for most tasks you may sometimes want to drop down to the code level, for example to add some logic to a property setter.

In fact, at run time a LightSpeed model is just code.  Even if you only use the visual designer, the actual runtime model is the generated code from the designer.

The easiest way to understand LightSpeed coding conventions is to sketch out a model in the designer, then examine the generated code.  You’ll see that it follows a very regular pattern, and you can copy that pattern in hand‑written code.

Creating Entity Classes

To create an entity class, define a .NET class which inherits from Entity<TId>.  The TId type parameter is the identity type of the class.  For example, to define a Customer class whose Id is an integer, write:

public class Customer : Entity<int>
{
}

Entity classes must have a public default constructor.  If you don’t specify a constructor, the C# compiler supplies a public default constructor, but if you specify a non‑default constructor, you’ll need to provide a default constructor as well.  (See below for Visual Basic considerations.)

The persistent state of an entity is defined by its fields.  It’s very important to understand that LightSpeed is interested in fields, not properties!  The designer blurs this distinction, because in most entities, every field is wrapped by a property and every property wraps a persistent field.  But when you hand‑write code it’s essential to understand it.  For example, it means you mustn’t use C# automatic properties, because the backing field for automatic properties is compiler‑generated and will have the wrong name:

public class Customer : Entity<int>
{
  public string Surname { get; set; } // Error – backing field will NOT be named Surname
}

Instead, you must explicitly create a field with the right name.  (LightSpeed also permits the underscore prefix.)

A persistent field in LightSpeed

public class Customer : Entity<int>
{
  private string _surname; // LightSpeed ignores underscore prefix
}

You can then create a wrapper property so that application code can access the persistent value.  The property getter can just return the field value, but the property setter must call the Entity.Set method.  The Set method is important because it is how LightSpeed knows that the field has changed.  This is essential for knowing that at entity needs to be saved, and to support application interfaces such as IEditableObject and INotifyPropertyChanged.

A wrapper property for a persistent field

public class Customer : Entity<int>
{
  private string _surname;
  public string Surname
  {
    get { return _surname; }
    set { Set(ref _surname, value); }
  }
}

You don’t have to provide a wrapper property and LightSpeed won’t care if you don’t.  LightSpeed only cares about the field, and about the Set method being used to modify it.

Because LightSpeed cares only about fields, not properties, LightSpeed attributes – for example, validation attributes, or attributes that control the database mapping – must go on fields rather than properties.  (The compiler will warn you if you make a mistake.)

Creating Associations Between Entities

In the designer, a one‑to‑many association is represented as a single arrow, which results at the code level in a collection, a backreference and a foreign key property.  In code, you need to create all of these fields – and, normally, wrapper properties – explicitly.  To represent a collection, use a field of type EntityCollection<T>; to represent an entity reference, use a field of type EntityHolder<T>.  (Foreign keys are just normal scalar fields, typically of type int or Guid.)

The collection and holder fields should be marked readonly, and initialised to new collection and holder instances.

Association fields always come in pairs.  If the Customer class defines a collection of Orders, then the Order class must define a reference to Customer.  These pairs are reverse associations.  LightSpeed will throw an exception at runtime if it can’t find the reverse for an association.  Furthermore, each EntityHolder<T> must be matched with a foreign key field, whose name is the same as the EntityHolder<T> field followed by Id.  For example, if the Order class has a holder named _customer, it must have a scalar field named _customerId.

A one‑to‑many association therefore looks like this in code:

Representing a one-to-many association

public class Customer : Entity<int>
{
  private readonly EntityCollection<Order> _orders = new EntityCollection<Order>();
}
public class Order : Entity<int>
{
  private readonly EntityHolder<Customer> _customer = new EntityHolder<Customer>();
  private int _customerId;
}

When application code accesses an association property, you need to ensure that the association is loaded.  To do this, call the Get method.  This loads the association – the collection or the associated entity – if required.  If the association is already loaded, Get doesn’t do anything.  You’ll usually call Get from a property getter.

Application code can update a collection using the Add and Remove methods.  To update an entity reference, you must call the Set method.  Set updates the contents of the EntityHolder<T> and updates other information such as the foreign key field.

The conventional property wrappers for a one‑to‑many association therefore look like this in code:

Property wrappers for a one-to-many association

public class Customer : Entity<int>
{
  private readonly EntityCollection<Order> _orders = new EntityCollection<Order>();
  public EntityCollection<Order> Orders
  {
    get { return Get(_orders); }
  }
}
public class Order : Entity<int>
{
  private readonly EntityHolder<Customer> _customer = new EntityHolder<Customer>();
  private int _customerId;
  public Customer Customer
  {
    get { return Get(_customer); }
    set { Set(_customer, value); }
  }
  public int CustomerId
  {
    get { return _customerId; }
    set { Set(ref _customerId, value); }
  }
}

Remember, as with simple fields, LightSpeed cares only about fields, not properties, so you’re not forced to follow this pattern or even to expose association properties at all.

One‑to‑one associations are implemented in the same way as one‑to‑many associations, except that you use an EntityHolder<T> at both ends.  The usage of the EntityHolder<T> is the same, and there must be a foreign key field at one end.

Normally, LightSpeed can match associations up with their reverse associations because there is only one association between any two classes.  If you have multiple associations between the same pair of classes, you must use ReverseAssociationAttribute to pair them up.

public class Customer : Entity<int>
{
  [ReverseAssociation("Customer")]
  private readonly EntityCollection<Order> _orders = new EntityCollection<Order>();
}
public class Order : Entity<int>
{
  [ReverseAssociation("Orders")]
  private readonly EntityHolder<Customer> _customer = new EntityHolder<Customer>();
  private int _customerId;
}

Many-to-Many Associations

As mentioned above, a many‑to‑many association in LightSpeed is represented by a through association.  A through association is implemented in terms of a one‑to‑many association to a through entity and a many‑to‑one association from the through entity to the target entity.  For example, suppose you want to model a many‑to‑many association between Contribution and Tag entities.  You would need a through entity, which we will call ContributionTag, and one‑to‑many associations from Contribution to ContributionTag and Tag to ContributionTag.

Most through entities contain nothing except the associations to the entities being linked, which are represented as the EntityHolder<T> ends of one‑to‑many associations.  As usual the foreign key fields are required as well.  So the ContributionTag entity would look like this:

Representing a through entity in code

public sealed class ContributionTag : Entity<int>
{
  private int _contributionId;
  private int _tagId;
  private readonly EntityHolder<Contribution> _contribution =
    new EntityHolder<Contribution>();
  private readonly EntityHolder<Tag> _tag = new EntityHolder<Tag>();
  // Wrapper properties omitted for brevity. Wrapper properties are optional
  // and could be left out if you do not expect to work directly with through
  // entities.
}

Conversely, Contribution and Tag each have a reverse association which is one-to-many: each Contribution can have any number of ContributionTags and each Tag can also have any number of ContributionTags. Here’s the relevant fragment of Contribution:

The underlying one‑to‑many association for a through association

public class Contribution : Entity<int>
{
  private readonly EntityCollection<ContributionTag> _contributionTags =
    new EntityCollection<ContributionTag>();
  // Wrapper property omitted
}

You would define a similar association from Tag to ContributionTag.

Finally, you can now implement the through association.  This is a field of type ThroughAssociation<TThrough, TTarget>.  The through association needs to be initialised with the EntityCollection representing the one-to-many association from the source entity (Contribution) to the through entity (ContributionTag).  To load the through association, call the Get method.  As with other associations, this is usually done in the property getter.

Implementing a through association

public class Contribution : Entity<int>
{
  private ThroughAssociation<ContributionTag, Tag> _tags;
  public ThroughAssociation<ContributionTag, Tag> Tags
  {
    get
    {
      if (_tags == null)
      {
        _tags = new ThroughAssociation<ContributionTag, Tag>(_contributionTags);
      }
      return Get(_tags);
    }
  }
}

Again, the Tag entity will contain similar code for its Contributions through association.

The through entity is a true entity in the model, so you can use it to hang data and behaviour relating to the association itself.  For example, to track who applied a particular tag to a particular contribution, you could put an AddedBy field on the ContributionTag entity.

Special Considerations for Visual Basic

A nice feature of .NET is the great interop between components written in different languages. LightSpeed is no exception and can be used just as easily from Visual Basic as from C#.

However, when hand‑coding entities in Visual Basic, there is one minor difference, which is due to Visual Basic classes initialising in a slightly different order from C# classes.  The difference is that you must manually call the LightSpeed Initialize method from the entity constructor, as follows:

Writing an entity constructor using Visual Basic

Public Class Status
    Inherits Entity(Of Integer)
    Public Sub New()
        MyBase.New(False)
        Initialize()
    End Sub
End Class

You only need to do this if you are hand‑coding entities.  If you use the designer then it is taken care of for you.

Another small wrinkle is that Get and Set, the LightSpeed Entity methods, are reserved words in Visual Basic, and must therefore be escaped with square brackets:

Calling the Get and Set methods from Visual Basic

Public Property StatusName() As String
  Get
    Return [Get](_statusName) ' note square brackets around Get
  End Get
  Set(ByVal value As String)
    [Set](_statusName, value) ' note square brackets around Set
  End Set
End Property

Again, if you use the designer, it will take care of this for you.

Creating Code Models from Database Tables

If you have an existing database schema, and you would prefer to develop your entities in code rather than using the designer, you can use the lsgen command‑line tool to create C# or Visual Basic classes from your database.  See the Appendices for instructions on using lsgen.

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