Home » Blog

rounded header

Archive for March, 2009

Mindscape MVC – Extensions for ASP.NET MVC and LightSpeed

Now that ASP.NET MVC has been released we expect to see lots of people interested in building web sites based on this new offering. We have already been hearing from lots of our LightSpeed customers who are doing just that.

What we and others have found is that there are some very useful extensions you can equip yourself with to help to help integrate your LightSpeed entities nicely in with your controllers and views to handle automatic unbinding, validation concerns and the like.

Mindscape community code

To this end we are setting up a community project with a set of useful extensions and samples which you can leverage when building your ASP.NET MVC sites using LightSpeed. We have posted this up as the first of our community code projects at http://www.mindscape.co.nz/code – I will be building up the library a bit with our bits as part of my blog series on ASP.NET MVC and LightSpeed. Justin Thirkell from Intergen has also sent through some of the bits they have been using to help automate their client side validation code using jQuery so I will get that in there shortly :)

Check out the project and we look forward to evolving it with your contributions as well. Join us over in the community forum for discussion relating to this effort.

Happy coding!

kick it on DotNetKicks.com

LightSpeed and SQL Server 2008

tag icon Tagged as LightSpeed

We are currently busy working through features for LightSpeed 3.0, and one of the ones on my plate is to add in a new provider for SQL Server 2008 which can take advantage of some of the capabilities we have in SQL Server 2008.

We have done a great deal over the recent minor versions to augment our provider capabilities, adding support for stored procedures and views but we would like to go further. So far, here is what we have added in to our SQL Server 2008 provider.

Support for Native Types

There are a number of new native types in SQL Server 2008 such as geography, geometry and the new date and time data types.

We now support these types and translate them accordingly into properties on your LightSpeed entities. Some of these map to existing CLR types such as datetime2 –> DateTime, however some of the other data types (geometry, geography) are actually all new CLR based types living in the Microsoft.SqlServer.Types assembly.

Here is an example of this at work – we have a Cinema entity which has a geography data type storing its physical location as per this schema:

Shot012

Here is the definition of the entity we get generated:

[Serializable]
[System.CodeDom.Compiler.GeneratedCode("LightSpeedModelGenerator", "1.0.0.0")]
public partial class Cinema : Entity<long>
{
  #region Fields
 
  [ValidatePresence]
  [ValidateLength(0, 255)]
  private string _name;
  [ValueField]
  private Address _address;
  [ValueField]
  private SqlGeography _geoLocation;
  private int _seats;
  private long _locationId;
 
  #endregion
 
  // other generated code omitted for brevity..
}

And here is what we can then do with it:

foreach (var cinema in unitOfWork.Cinemas)
{
  Console.WriteLine("{0} is at {1},{2} - {3}", cinema.Name, cinema.GeoLocation.Lat, cinema.GeoLocation.Long, cinema.Address.Street);
}
 
unitOfWork.Cinemas.First().GeoLocation = SqlGeography.Parse("POINT (45 45)");
unitOfWork.SaveChanges();

Support for CLR based UDTs

Along a similar line to our support for SqlGeometry and SqlGeography, we also support custom CLR based UDT’s. These might make sense for you in place of a ValueObject.

Here is an example – given our Cinema entity above, you will notice the Address column is of an Address data type, this is a custom CLR type I have created and deployed.

Here is the class definition for that UDT:

[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedType(Format.UserDefined, MaxByteSize=8000)]
public struct Address : INullable, IBinarySerialize
{
  private bool _isNull;
 
  private string _street;
  private string _city;
  private string _country;
 
  public string Street { get { return _street; } set { _street = value; } }
  public string City { get { return _city; } set { _city = value; } }
  public string Country { get { return _country; } set { _country = value; } }
 
  // other code omitted for brevity
}

And like with the SqlGeography above it is just natively available to make use of:

unitOfWork.Cinemas.Skip(1).First().Address = new Address() { Street = "124 Foo St", City = "Wellington", Country = "New Zealand" };
unitOfWork.SaveChanges();

What else should we add in?

We still have plenty of time before LightSpeed 3.0 is going to go out the door, so I thought I would open the floor to you to suggest some additional SQL specific capabilities that we should be adding in. A QueryNotification hook to refresh the L2 cache? Support for Table Value Parameters in stored proc calls? Some kind of handling for FILESTREAM based columns?

We welcome your feedback :)

User feedback – what’s yours?

Omar, a recent new Mindscape customer and LightSpeed user has written a fantastic blog post about his impressions of Mindscape LightSpeed. We always appreciate when our users blog about their experiences with our products – it’s the best form of marketing that a small business can get when selling developer tools. If you write about LightSpeed do let us know, we all get a buzz out of seeing people enjoying our products.

A snippet from Omar’s LightSpeed Review reads:

LightSpeed has changed my mind on how good ORMs can be. The guys at Mindscape are so helpful and work with customers on personal basis and will always take the time to listen to your problems. The support is just great. While I am not saying that LightSpeed is the answer to every problem out there it is definitely a huge leap in the right direction. Keep doing what you do best Mindscape and keep the new functionalities and goodness flowing. If you got me to become an ORM user then I will go as far as saying “NHibernate, you loose”.

You can read the post in its entirety here.

We have always had some testimonials for LightSpeed on the site but have been slow to update that page or to post testimonials for other products (we do get them, we’re just quite busy! :-). So, in an attempt to remedy this situation and to make a bit more noise about the successes that our customers are having with our products we’re looking to publish case studies for users who wish to take part. This can be for any product that we have built – not just LightSpeed.

This is an opportunity to provide us with feedback on what we’re doing right and areas that we can improve. It’s also a good chance to publicize the products you’re building on Mindscape tools or to highlight your business to others looking at using Mindscape tools.

If you’re interested, get in touch by emailing jd@mindscape.co.nz and I’ll send you out a questionnaire that will act as the basis of a case study.

Thanks in advance!

Custom timestamps in LightSpeed

tag icon Tagged as LightSpeed

LightSpeed has built-in support for tracking the creation and last update times of entities, just by creating fields and columns named CreatedOn and UpdatedOn, or setting a couple of options in the designer. By default, the creation and update times are recorded using the local time of the machine where LightSpeed is running.

But what if you’ve got multiple sites in different time zones? Then you can’t be sure what a timestamp of, say, 10am actually means. So we’ve added an AutoTimestampMode property to LightSpeedContext. This still defaults to Local, but can also be set to Utc to record times in UTC/GMT, so that you can know exactly what the timestamps mean even when there are multiple time zones involved.

That covers most cases, but you might still not be happy. One customer wanted, in his test suite, to be able to control the recorded timestamps, so that he didn’t get unpredictable timing-related test failures. You might have a policy of storing times in a fixed but non-UTC time zone, for example Pacific time. We can’t anticipate all those requirements, so we’ve added an additional Custom AutoTimestampMode. If you set the Custom mode, you must also set LightSpeedContext.CustomAutoTimestampStrategy, to a custom strategy object that implements IAutoTimestampStrategy.

IAutoTimestampStrategy has just two members: Mode, which for custom implementations should always return Custom, and GetTime, which should return the desired timestamp. Thus, in the test scenario, GetTime might return a fixed time, or return times off a queue set up in the constructor; you could even use a mocking framework to specify timestamps within each unit test. In the Pacific time scenario, GetTime would get the UTC time and convert it to the Pacific time zone.

You probably won’t need custom timestamps very often. Most people prefer local time because it’s easy to interpret, or UTC because it’s consistent and portable. But if you do need it, it’s all in the current nightly builds.

Testing with LightSpeed, Feedback needed

tag icon Tagged as LightSpeed, Products

Testability of code is something that’s very important in software development and with LightSpeed becoming the base framework for more and more domain models and applications we’re receiving increased interest in how to more easily test LightSpeed entities and other LightSpeed aspects.

In this post I want to achieve two things: Show you how to use Rhino Mocks to mock entities and give you an intro into changes we’re planning for LightSpeed 3.0 around testability (and hopefully get your feedback on!).

Mocking, stubbing and all that jazz

So, first of, mocking out Entities or, more appropriately, stubbing them. One of our fantastic customers, Admeta, who are relying on LightSpeed to enable flexibility and speed of improvement to their intricate domain model of a real-time advertisement revenue improvement system, emailed in this morning with some examples of work they have been doing to stub out a repository and therefore override the interactions with the database to use in memory objects.

orderRepositoryStub.Stub(repos => repos.FindOne(0)).
                IgnoreArguments().
                Return(
                    new OrderStub()
                    {
                        Id = orderId,
                        IsConfirmed = true,
                        OrderReference = 10049346,
                        SalesPerson = new Person { Name = "JD" }
                    });

In this code snippet you can see that we’ve created a stub that when calling the FindOne method, we’re returning a pre-packaged OrderStub object with the settings we want. No touching the database. But what about if somebody calls Save() on the repository?

orderRepositoryStub.Stub(repos => repos.Save(new Order())).
                IgnoreArguments();

This instructs the Save method, when passing in an Order, to ignore the request and therefore not touch the database. One thing you may have noticed though is that we take in Order, when previously we were retrieving OrderStub – why is that? Lets look at the definition of OrderStub:

[Discriminator(Attribute = "OrderNumber", Value = "not a number when testing")] 
// NOTE: See notes below about why this attribute is in use.
public class OrderStub : Order
{
    [Transient]
    private int _overrideId;
 
    public new int Id
    {
        get { return _overrideId; }
        set { _overrideId = value; }
    }
}

Here we can see that we’re able to shadow the Id field – LightSpeed doesn’t allow you to control the Id field on a real Order entity but shadowing is enough for our test purposes. The class is based upon Order, so interchangeable with Order and therefore we can work with it happily as an order.

But what’s the deal with the Discriminator? Well, LightSpeed will try to walk the structure of the type hierarchy when it loads Order and it will see that OrderStub uses Order. It will then inspect the associations of Order and in there you’ll run into issues – an exception will be thrown because it will be looking for a discriminator attribute. In this case we can attribute up our stub to work around this issue but it’s a hack and is exactly the sort of thing that we want to tidy up in LightSpeed 3.0.

All in all, this code which was passed to us shows one customer’s way of working with mocking frameworks to create in memory testing by decoupling from the database specific components of LightSpeed. We love getting feedback and examples of what our customers are doing – if you’re one of them then do feel free to show us what you’re doing :-)

LightSpeed 3.0 Enhancements

In LightSpeed 3.0 we plan to do several things to enhance testability. The first off is the addition of the Mindscape.LightSpeed.Testing namespace which includes utility code to aid in accessing parts of LightSpeed that are normally abstracted away. For example, we are including an EntityFactory to allow you to create entities with a given Id and EntityState:

public static TEntity Create<TEntity>(EntityState entityState, Object id)
public static TEntity Create<TEntity>(EntityState entityState)

Why is this under testing and why do we not allow setting these normally on the entity? LightSpeed manages the state and identity internally, saving you the pain of having to do so and ensuring that your entities are being managed correctly. However it can become a pain when you’re wanting to undertake unit testing.

We are also looking at the visibility of some methods and classes as well as adding pluggability to some sub components of LightSpeed (e.g., plug in a custom time provider when you want to control the values being set on CreatedOn, UpdatedOn, DeletedOn etc).

Your feedback

Your feedback is extremely important to us and guides much of what will make it into future versions of LightSpeed. If you have a particular view on testability with LightSpeed then please drop a comment on this post so that we can factor it in.

kick it on DotNetKicks.com

Data Products Visual Controls Community Store
LightSpeed ORM
NHibernate Designer
SimpleDB Tools
SharePoint Tools
WPF Elements
WPF Diagrams
Silverlight Elements
Forums
Blog
Register
Login
Subscribe to newsletter
Buy Now
My Account
Volume Discounts
Purchase Orders
Contact Us