Mindscape Mindblog

Archive for June, 2009

Refactoring in the LightSpeed designer

tag icon Tagged as LightSpeed

If you’ve used Visual Studio for any length of time, you undoubtedly make heavy use of refactoring. Even the simple refactoring of renaming a class or method and having Visual Studio automatically update all references is a huge time-saver. If, however, you use the LINQ to SQL or Entity Framework designer, and you rename a class or property in the designer, the references to that class or property in your code don’t get updated: you need to go through and fix them up by hand. Until recently, we admit, that’s also been the case in the LightSpeed designer. But not any more!

In current nightly builds, you can right-click an entity or property and choose Refactor > Rename. LightSpeed will then not only rename the entity or property, it will also update any existing references. The Refactor > Rename command also gives you the option to keep the existing name as the “database name” (the Table Name for entities, the Column Name for properties), so that you don’t need to remember to remap the entity or property by hand. (Of course, you’ll want to turn this option off if you also intend to rename the column in the database.)

Rename refactoring in the LightSpeed designer

The Refactor menu also offers a couple of other time-saving utilities. One that we’re going to find really handy is Convert to Manual Implementation. This is useful when you want to customise the implementation of a property, for example by adding your own business logic or validation in the setter. Convert to Manual Implementation marks the property to be excluded from code generation in future, and copies the existing generated property code to a partial class to provide you with a starting point that you can then edit to meet your requirements. It even copies attributes such as column name mappings and validation attributes.

Results of the Convert to Manual Implementation refactoring

Finally, Create Partial Class quickly creates a partial class declaration for you, and Extract Interface allows you to rapidly declare an interface containing selected properties of an entity. (Extract Interface is available only in C# projects.)

One small caveat. Most of these refactorings need access to the generated code, and the code is only generated when you save the .lsmodel file. So if you try to refactor a model with unsaved changes, the designer will do its best, but you may get an error if refactoring needs to access one of those unsaved changes. (Some refactorings may also fail if you’re using a sufficiently radical custom template.)

We’d love to hear your feedback on these refactoring features and whether there are any other similar refactorings you’d like to see in LightSpeed. You can get the latest nightly of the free Express edition here, or retail editions from the store.

Shout it


kick it on DotNetKicks.com

Visualising inheritance graphs in the LightSpeed designer

tag icon Tagged as LightSpeed

We’re continuing to add filtering capabilities to the LightSpeed designer, and have recently added a couple of new features.

The first feature is to show the inheritance graphs of the selected entity or entities. This shows all entities derived from the selected entity, and all of its base types. For example, consider this inheritance hierarchy:

Person hierarchy in LightSpeed designer

Here’s the same model, with “Contractor” entered into the filter box and the new Show inheritance option selected:

Contractor inheritance graph

As mentioned, if you enter an intermediate or base class then the designer shows all the derived classes as well. Here’s the model filtered on the “Employee” inheritance graph:

Employee inheritance graph

The second new feature is the ability to invert a filter. So if you want to show all entities except a particular one, you can now do so. This can be handy for excluding common base classes which would otherwise have lines to them from everywhere in the diagram, creating clutter. To do this, enter an exclamation mark (!) in front of the filter criterion:

Inverting a filter

(We don’t have a menu helper for this yet — you’ll just have to remember it!)

Both of these features are in the current nightly build — free Express edition here, or commercial editions from the store.

Join queries in LightSpeed 2

tag icon Tagged as LightSpeed

Join support is one of the most frequently requested features for LightSpeed, and it’s coming in version 3, but what people don’t always realise is that you don’t always need a join for a join query. LightSpeed 3 join support will enable you to pull back data from across multiple tables; but if all you want to is to pull back entities from a single table using criteria from other tables, you can often do that today.

Let’s look at a simple example of a video sharing site, based on something that came up in the forums recently. In this model, the main entities are Contributions. Each Contribution is associated with a Member (who uploaded it). In addition, there is a many-to-many (through) association between Contributions and Tags, via a ContributionTags through entity.

Simple video sharing model

Now suppose you want to find all the Contributions uploaded by a Member named “t-dogg” and tagged with a Tag named “sheep.” Initially it might seem like you need a join for this, or at least a sequence of nested selects, but in fact you can do it efficiently in a single LINQ query:

from ct in UnitOfWork.ContributionTags
where ct.Contribution.Contributor.Name == "t-dogg" && ct.Tag.Value == "sheep"
select ct.Contribution

The trick here is to work around LINQ’s collection issues by finding a start point where all the associations are many-to-one. In this case, ContributionTag has many-to-one associations with Tag and with Contribution, and Contribution has a many-to-one association with Member. So we can write the query in terms of ContributionTag objects without needing to do a join or an explicit subselect. Then we can project the results along the many-to-one association to Contribution to get the Contributions instead of the ContributionTags.

The core API allows another syntax for the same query which you may find more natural:

UnitOfWork.Find<Contribution>(
  Entity.Attribute("Contributor.Name") == "t-dogg"
    && Entity.Attribute("ContributionTags.Tag.Value") == "sheep");

Here it’s clearer from the Find call that the query is interested in Contributions, not in ContributionTags. Notice also that LightSpeed is able to traverse the ContributionTags collection association without you needing to write an explicit join or subselect.

What LightSpeed can do automatically doesn’t cover every possible join query, and of course if you want to return data from multiple tables you currently have to use a view or a stored procedure rather than a join. But for simple queries that return data from a single table but need to join to other tables only for the “where” criteria, there’s a good chance you can build a LightSpeed query to do the job.