LightSpeed 1.1 Released

Today we’re pleased to announce the release of LightSpeed 1.1. This is a major release incorporating many new features and improvements all based on real-world customer feedback. Let’s take a look at some of the highlights…

h3. Soft Delete.

We now support “soft delete”. With soft delete entities are never physically deleted, but instead marked as deleted using a timestamp field.

To enable soft delete simply add a _DateTime?_ field called “deletedOn” (or _deletedOn) like so:

// class Customer
 
private readonly DateTime? _deletedOn = null;
 
public DateTime? DeletedOn
{
  get { return _deletedOn; }
}

Now when we query _Customer_ like so:

long count = Repository.Count<Customer>();

The sql produced looks like this:

SELECT
  COUNT(*)
FROM
  Customers
WHERE
  Customers.DeletedOn IS NULL

Of course, the extra SQL criteria are also applied appropriately when using eager loading.

If you need to get hold of entities marked as deleted then you can tell LightSpeed to omit the checks. To do this simply set the _IncludeDeleted_ property on the _Query_ object.

h3. Polymorphic Querying.

In 1.1 we’re making it easier to query specific types in an inheritance hierarchy. Previously, if we wanted only _GoldCustomers_ from our _Customer_ hierachy, we would have to manually add the discriminator criteria to our query. Now we can just ask LightSpeed to return just the _GoldCustomers_ (or any descendents of).

IList<GoldCustomer> = Repository.Find<GoldCustomer>();

And the SQL produced will look something like:

SELECT
  Id,
  CustomerTypeId,
  Name,
  Discount
FROM
  Customers
WHERE
  Customers.CustomerTypeId = 2  -- 2 for Gold Customers

h3. Validation

Validation received much love in 1.1:

We’ve added a _Validating_ event that gives you a little more control over the validation of an entity. Specifically, this event is fired just before an entity is validated and gives you the option of skipping validation for the entity.

Based on customer feedback, we also changed the validation algorithm so that it now walks the graph of associated entities. Let’s say our _Customer_ class has an associated collections of _Purchases_ and that a _Purchase_ must have a positive _Amount_. _Customer_ is our aggregate root here so our code may look something like this:

Customer customer = Repository.Find<Customer>(1); // find customer with id == 1
customer.Purchases.Add(new Purchase());  // oops, didn't set the purchase amount
 
Repository.CompleteUnitOfWork();

As expected, _CompleteUnitOfWork_ throws a _ValidationException_ because our new _Purchase_ has an invalid _Amount_. The error message looks something like this:

_Mindscape.LightSpeed.Validation.ValidationException : The object [Customer[Id=1, EntityState=Modified]] could not be saved because it is invalid.

The errors are:

  Purchases item 0 is invalid

    Amount is required_

We also added scoping to the _ValidateUnique_ attribute. This allows you to more finely limit the range of a uniqueness validation check. Usually, a _ValidateUnique_ rule results in LightSpeed issuing a query similiar to:

SELECT
  COUNT(*)
FROM
  Customers
WHERE
  (Customers.Name = 'Ivan' AND Customers.Id <> 42)

If however, we were only concerned with _Name_ being unique within the scope of _CustomerTypeId_, we would apply the validation like so:

[ValidateUnique("CustomerTypeId")]
private string _name;

With the scope applied LightSpeed adds the scope check to the resulting validation query:

SELECT
  COUNT(*)
FROM
  Customers
WHERE
  (Customers.Name = 'Ivan' AND Customers.Id <> 42 
  AND CustomerTypeId = 2) -- Ivan is a Gold Customer

h3. Default Order Attribute.

We’ve introduced an attribute to allow you to control the default order applied when querying. The new attribute can be applied at the class or association level like so:

[OrderBy("Subject")]
public class Customer : Entity<int>
{
  [OrderBy("Amount ASC")]
  public readonly EntityCollection<Purchase> _purchases
    = new EntityCollection<Purchase>();
 
  //...
}

At the class level, LightSpeed will apply the default ordering to any queries that have no explicit order specified. At the association level, as with _Purchases_ in the example, LightSpeed will apply the default ordering when loading the associated collection (eager or lazy).

h3. Performance Improvements.

We refactored some core components of our mapping engine. You should notice some nice performance improvements across all areas of the framework.

h3. Inheritance Mapping.

We fixed quite a few edge case bugs around inheritance mapping. Additionally, we made some improvements to how discriminator attributes are handled:

Discriminator fields are now automatically initialized:

Customer goldCustomer = new GoldCustomer();
// goldCustomer.CustomerTypeId == 2

Discriminator fields can now be enums:

[Discriminator(Attribute = "CustomerTypeId", Value=CustomerTypes.Gold)]
public sealed class GoldCustomer: Customer
{
}

h3. Read-only Fields.

Any field declared _readonly_ won’t be included in any save operations. This is useful for derived columns or if you are backing on to an updateable view instead of a table.

h3. Identifiers Only Query Option.

The LightSpeed _Query_ object now contains an _IdentifiersOnly_ property. Set this to _true_ and LightSpeed will return a collection of object identifiers rather than complete entities.

h3. Nested Unit of Work.

Occasionally it is useful to be able to have multiple units of work alive within the same scope. LightSpeed 1.1 now supports this through the concept of a nested unit of work. To create a nested unit of work simply call the _Repository.BeginUnitOfWork_ method. This method effectively pushes a new unit of work on to an internal unit of work stack making it the new current unit of work. Calling _Repository.CompleteUnitOfWork_ will dispose the nested unit of work and pop it from the stack causing the previous unit of work (if any) to become current.

h3. Samples & Documentation

We’ve spent a good deal of time in 1.1 trying to make the documentation and samples even better. We’ve included a new VB sample and also included a small sample illustrating how LightSpeed passes the “Mats Challenge”:http://www.matshelander.com/wordpress/?p=55.

h3. Special Offer

To celebrate this release we’ve decided to run a limited time special offer. Get LightSpeed Standard for $99 and LightSpeed Professional for just $299.

So what are you waiting for? Go grab the free “LightSpeed Express”:http://www.mindscape.co.nz/Downloads/LightSpeedExpress.msi version and kick the tires. As always, we’d love to hear any feedback.

Cheers,

Andrew.

kick it on DotNetKicks.com

One Response to “LightSpeed 1.1 Released”

  • […] industrious people over at Mindscape have released version 1.1 of their LightSpeed domain modeling/ORM framework. I used LightSpeed while it was in beta with my […]

  • Leave a Reply

Archives

Join our mailer

You should join our newsletter! Sent monthly:

Back to Top