LightSpeed – A Commercial ORM For .NET
LightSpeed is a commercial ORM for .NET that boasts of several features such as Entity Serialization, a robust VS designer, built-in LINQ support, support for DTOs and more. We got in touch with John-Daniel Trask, co-founder of Mindscape (LightSpeed’s maker) to speak more about the product and ORMs in general.
InfoQ: There are already a lot of open source and commercial ORM products for .NET - why did you decide to create a new product?
JD: LightSpeed was Mindscape’s very first product, and it came out of our previous experience in the IT services sector. We’d worked with existing object-relational mappers (ORMs), but there wasn’t much choice in the .NET space at the time. It was pretty much NHibernate or build your own from scratch, and a lot of organisations were building their own. We felt that the performance and experience of working with existing ORMs wasn’t that good, and we believed that businesses would be willing to pay for a good, easy to learn, high performance ORM that would save them time relative to other offerings or to the DIY approach.
InfoQ: What according to you are the key things that an ORM should handle?
JD: The basic purpose of an ORM is to provide a great mapping between a database and the object world, so of course it needs to do that well.
Beyond that, performance is very important. One common complaint is that ORMs don’t perform well, though we’re not convinced this is true. A good ORM can automate techniques such as object hydration, query batching, efficient query generation, eager loading, intelligent caching, and so on, which can make ORM-based code perform just as fast as code that’s been ground out by hand.
Productivity is also crucial. Using an ORM isn’t about saving machine time, it’s about saving development time – building things faster, eliminating whole categories of mistakes, enforcing good practices, enabling rapid and reliable testing and deployment. For example, LightSpeed automatically parameterises queries, which pretty much eliminates SQL injection attacks compared to hand-coded SQL. And we’ve all had to spend time getting a model to implement strong validation, or data binding notifications, or edit-rollback. With LightSpeed we worked hard to push all of these types of concerns into the “it just works” category. Moving from raw data access code to using an ORM should be like moving from assembler to C# or Java. Maybe you’re giving up a little bit of performance, but it’s less than you think, and you make it back a hundred times over in productivity!
One final thing that’s specific to .NET ORMs is LINQ support. LINQ has taken off so much it’s hard to remember trying to work without it. So it’s important to have a really solid LINQ provider. Building a bad LINQ provider is hard. Building a good LINQ provider is *really* hard. We've been constantly improving the LINQ provider in LightSpeed for years and it's something we're super proud of. LINQ support has become an expected feature in the .NET developer toolbox so having an ORM that either doesn't support LINQ or does a poor job is not acceptable.
InfoQ: Does LightSpeed support something similar to EF code-first with POCOs?
JD: Model-first and code-first are very similar with the concept being that a developer expresses the model in code before a database structure exists. LightSpeed certainly supports model-first and has for many years however it is reliant on working with the LightSpeed model designer to create and manage the database changes as well as create the classes based on the model defined. EF code-first takes model-first a step further than our approach and allows developers to just write the classes themselves and have database updates generated from those classes without a designer. We get almost no requests for adding this support as it's a significant productivity loss to go from having your classes created for you to having to hand write every entity your application requires.
With regards to POCOs, we don't push them as a default. LightSpeed entities depend on an 'Entity' base class because frankly, we believe this provides huge value to the developer. Remember, ORMs are about productivity. We see folks who love POCOs spend hours managing T4 templates just to generate classes that support, say, INotifyPropertyChanged, or track changed fields, or handle validation (or worse yet, hand code all these concerns without a code generator!). Yuck - you have better things to do that writing that sort of code by hand. Our experience is that the trade-off of having – shock horror – an extra level of inheritance is well worth it: LightSpeed developers typically like LightSpeed because they can focus on getting actual problems solved rather than manually integrating or writing their own plumbing code.
With that said, distributed scenarios benefit nicely from POCOs, so LightSpeed supports two approaches to distributed development:
- Entity serialization over the wire and a 'DistributedUnitOfWork' so that developers can write LINQ queries on the client and LightSpeed will automatically pass it to the server, run the query, send it back. We also do smart things like only sending back changed entities to make things faster. This approach is a more fully featured and potentially seen as a bit "magic".
- DTOs - Not only can the LightSpeed Designer generate DTOs for users, but we provide methods to make it easy to import a DTO into a fully fledged Entity object on the server. Simple, not so magic, but what some developers prefer.
InfoQ: What about Automatic Migrations?
LightSpeed supports something better than automatic migrations.
LightSpeed is the only ORM that extends Visual Studio to add integrated schema migration management. This includes capturing changes, displaying what migrations exist, executing them against the database and generating change scripts (in whatever flavor database you're using). Of course, servers shouldn't have Visual Studio installed on them so we include command line tools for running the migrations against your production databases, or you can integrate them into your application using an API.
Migrations is just one part of the story -- you typically make a migration once you're sure your model changes are what you need. The LightSpeed designer has supported what we call "360 database round tripping" since we first released it, and our users absolutely love it. What it means is that if you're a developer who likes to work model-first, you can model your domain, right click - "update database" and the LightSpeed Designer will perform a difference operation between your development database and the model and check with you that you want to apply the changes. Click 'OK' and you're done, database is up to date.
But what about if you work database-first? Easy, right click on your model, "Update from database", again the LightSpeed Model Designer will find the changes and show them to you before you confirm you want them applied to your entities. The fantastic thing is that you can have a mix - if some developers like model-first and some like database-first, they can work how they like, all at the same time, and it will just work.
InfoQ: You mentioned in one of your posts that LightSpeed supports even up to 2000 entities in a single Entity Model Designer, and still manages to keep it user friendly - could you explain how you achieved that?
JD: Well, 2000 entities in a single model is never going to be really user friendly, but we’ve done a lot of things to help users tame very complex models.
For example, we provide a quick way to search a model for the entity you need – just start typing its name and we’ll filter down and zero in on the matching entity. You can then expand that to include associated entities or the entire aggregate. If you want to see whole subdomains – sales or logistics, say – rather than individual aggregates, you can tag up your entities and filter by tag. So it’s easy to strip the model back to just the few entities you’re interested in right now. You can also span a model across multiple files – file per subdomain, for example – which isn’t as integrated but can help with concerns such as source control if several people are working on different bits of the model at the same time.
One feature that seems trivial but can really help with big models is entity colouring. It’s not unusual to have relatively few key business entities in your model, with the rest of the model orbiting around those key entities. Display those entities in a distinctive colour and suddenly they’re easy to find at a glance – they stand out from the noise.
At the lower level, we’ve also invested quite a bit in efficiently getting the database metadata. For example, we avoid pulling down metadata for tables we don’t need – this can make a huge difference when you’re dealing with sprawling legacy databases.
So this means we can do schema round-tripping efficiently even in larger cases.
InfoQ: Is there a simple migration path for applications currently using NHibernate or Entity Framework without making too many code changes?
JD: This depends a lot on how a developer has architected their application.
If a developer has used LINQ (e.g. uses Entity Framework or LINQ to SQL) then it's quite easy to do. We've had customers who have converted significant applications built on top of the Entity Framework to LightSpeed in only a couple of hours. That was made easy because queries do not need to be re-written if they're already in LINQ, the user only needs to replace session objects with a LightSpeed UnitOfWork, migrate the model to a LightSpeed model and add some configuration to their application. On the other hand, if a lot of the query logic is in HQL (Hibernate Query Language), then you have a bit more work to do!
In terms of model migration, LightSpeed includes features to assist in the migration of Entity Framework and LINQ to SQL models to LightSpeed. Dragging an EDMX file or LINQ to SQL model file onto a LightSpeed model surface will result in the LightSpeed designer reading the model and populating itself. Keep in mind however that model migration is often the beginning of the process rather than the end! Testing is paramount – for example, you may run into differences in the LINQ providers particularly with very complex queries.
And just like in any migration, you’ll want to get the most out of the platform you’re moving to. For example you’ll probably want to move your validation code over to the integrated validation framework, set up eager loads to make your queries more efficient, that sort of thing. But between the common LINQ syntax and the model import support, it’s pretty easy to at least spike out a migration to LightSpeed and see whether it’s a good fit for your application.
InfoQ: What normally requested features, according to you, falls outside the responsibility of an ORM and why?
JD: We encounter developers who want the ORM to entirely replace having to work with their database. For example, requesting that the ORM manage database replication, something that is typically a database concern. While certain features that fall outside the scope could in theory be added to an ORM it would be very few users who take advantage of those features and thus it would be cost prohibitive to include them. Most feature requests that we will not support fall under this category.