I finally found some time to migrate two of my pet projects from the “Oslo” May CTP to the new SQL Server Modeling November 2009 CTP. I didn’t publish the sources so far, but I will soon.
Work Breakdown Structure
The first application that I want to migrate is a so-called work-breakdown-sheet (WBS). Originally it was a Excel sheet containing tasks and task estimates. Some smart calculations apply a set of statistics to give a forecast that is as close as possible to the real effort required.
The technologies I wanted to try out with that were mostly “Quadrant” and the “Repository”, now SQL Server Modeling Services. Also I wanted to test the team on their ambitious goal to make something that gets close to the experience of Access in ease of use.
The project contains of a set of “M”-based models and functions as well as some basic “Quadrant” customization. No plain old C# code needed, so far.
The basic domain model expressed in M (May CTP):
type Project {
Name : Text;
};
type Story {
Name : Text;
Project : Project;
};
type TaskGroup {
Name : Text;
Story : Story;
};
type Task {
Description : Text;
Comment : Text?;
Group : TaskGroup;
};
type Estimate {
BestCase : Double;
AverageCase : Double;
WorstCase : Double;
} where value.BestCase < value.AverageCase
&& value.AverageCase < value.WorstCase;
I’ll write an introduction to the project soon. But now, I’ll just log the changes I had to make in order to be able to get it running on the new CTP.
The Project File
In May, both Visual Studio and Intellipad used a *.mproj-File to collect multiple models in a project. In November this is embedded in a *.csproj-File. The easiest thing was to create a new “Oslo Library” in VS 2010 and just add the files that previously were linked in Wbs.mproj.s
Now I got the project both in Visual Studio 2010 and in Intellipad:
Now lets build.
Syntax Changes
Lets walk through the errors I get, and how the syntax has to be changed to fix them.
- First surprise. Intellipad builds the project without complaining. Well this message still leaves me unconfortable: Skipping target "MCompileCore" because all output files are up-to-date with respect to the input files.
So lets switch over to VS. The Messages I get are:
- Error: Expected a ‘;’ to finish the extent declaration.
- Error: Expected a ‘;’ to finish the computed value declaration or a ‘{‘ to start its body.
- Warning: The ‘item’ expression is being deprecated. Please replace with an appropriate ‘value’ expression.
Those were easy to fix. Although the error messages look more explaining then they are.
Actually both first errors had to do with the new collection syntax. This goes for extent declarations as well as functions. This, for example:
TaskEstimates() : PersonalTaskEstimate* {
from e in RawTaskEstimates
select MixEstimates(CalculateEstimate(e), e)
}
Needs to be changed to:
TaskEstimates() : {PersonalTaskEstimate*} {
from e in RawTaskEstimates
select MixEstimates(CalculateEstimate(e), e)
}
The warning about the deprecated item keyword in:
RawStories : (Story & HasFolderAndAutoId)*
where item.Project in RawProjects;
is solved by using value plus making sure, that the constraint goes inside the collection.
RawStories : {((Story & HasFolderAndAutoId)
where value.Project in RawProjects)*};
After having fixed those I get a next set of errors:
- The left-hand side ‘value.BestCase’ of ‘in’ must be compatible with the collection element type ‘LifelikeEstimateNumber’.
This seems to be a implicit change enforced by the new type checker in the current CTP. This is the “invalid” code:
type LifelikeEstimateNumber : Double where value < 24
|| value in SomeFibonacciNumbers;
type SomeFibonacciNumbers : {55, 89, 144, 233, 377, 610};
The problem here is, that the compiler doesn’t infer that SomeFibonacciNumbers actually is a collection of Doubles. So we have to tell her.
There are different ways to do so. We can either ascribe the first value in the collection to a Double by writing:
{55: Double, 89, 144, 233, 377, 610}
or we could ascribe the whole collection to a collection of Doubles
{55, 89, 144, 233, 377, 610} : {Double*}
or we can mix it with a collection of Doubles:
{55, 89, 144, 233, 377, 610} & {Double*}
I don’t really know, what the differences will be. I’ll just go for the last one, because it looks so nice 🙂
Project References
The next problem is, that my references to models from the “Repository” and “Quadrant” can’t be found. Sure, I didn’t copy the references from the mproj-file, either. As described here, you now have to reference dll files instead of the mx-files that where needed in May.
In my case, I needed a reference to “C:\Program Files\Microsoft Oslo\1.0\bin\Repository.dll” in order to support the SQL Server Modeling Services type HasFolderAndAutoId.
Now all the “M” code seems to be ok. The only thing is, that some concepts do not compile to SQL.
For this code:
type LifelikeEstimateNumber : Double where value < 24
|| value in SomeFibonacciNumbers;
type SomeFibonacciNumbers : {55, 89, 144, 233, 377, 610} & {Double*};
type TaskEstimate : (Estimate & {
Task : Task;
}) where value.BestCase in LifelikeEstimateNumber
&& value.AverageCase in LifelikeEstimateNumber
&& value.WorstCase in LifelikeEstimateNumber;
i get the following error for each occurence in the last three constraints:
- Not yet implemented: There is no SQL expression generator to handle the expression ‘TypeRef: Reference, resolve to get the target’.
It seems, that the constraint expressions can’t handle types completely. I’ll just refactor that to an inline expression plus an extent for the allowed high estimates:
AllowedHighTaskEstimates : {Double*} {
55, 89, 144, 233, 377, 610};
type TaskEstimate : (Estimate & {
Task : Task;
}) where
(value.BestCase < 24
&& value.BestCase in AllowedHighTaskEstimates)
&& (value.AverageCase < 24
&& value.AverageCase in AllowedHighTaskEstimates)
&& (value.WorstCase < 24
&& value.WorstCase in AllowedHighTaskEstimates);
Build succeeded!
Well I cheated a little bit, because I removed the models that drive the quadrant customization. But since those have changed completely anyway, I’ll just rebuild the requirements.
Deployment
For the May CTP I had a bunch of batch files to manage the build and deploy process. This was also, because I had to install a external SQL function before deploying my module. Lets see how this works with the deployment integration in Visual Studio 2010.
I configured the connection string in the M Deploy settings to a local database called ‘WbsTestRepository’. But trying to deploy the solution fails with a couple of errors. It seems, that the repository is not deployed automatically, allthough I added a project reference.
Repository Issues
In Wbs I want to use the Repository (now SQL Server Modelling Services) Rolders as well as the catalog which stores data about my models.
You still need to install the “Repository” on your database using the command line. This should be necessary only once, though.
The commands I ran were (described here):
'create a clean db
mx create /d:WbsTestRepository /s:.\SQLExpress /force
'install the rep
mx install Repository.mx /database:WbsTestRepository /server:.\SQLExpress
But now redeploying in VS yields another expected error:
- error M6040: Sql Exception: Cannot find either column "itemis.Wbs" or the user-defined function or aggregate "itemis.Wbs.Power", or the name is ambiguous.
Wbs needs the power-function to compute some values. Since M doesn’t know about it, and neither can express it natively, I had to model an so called extern:
extern Power(Expression : Double, Power : Integer32) : Double;
This just makes a concept available to M that has to be implemented in SQL. Since we want to ensure this in the installation, we have to compile it along with the M files. This is done by adding a SQL file containing the “create function [itemis.Wbs].[Power] …” script and set the compile action to “MPreSql”.
As I almost expected, redeploying the model doesn’t work. I’ll post a workaround for that soon.
- error M6040: Sql Exception: The module ‘itemis.Wbs’ is already present in the database.
But for now we just put the two lines in a batch file to recreate a fresh repository before each deploy.
The next problem I run into is:
- Sql Exception: Target folder must be specified.
There are two ways to add a target folder to your initial values. The documented one suggests adding your Folder to the FoldersTable and then specifying that value in every single instance. The much cleaner and simpler is, too set the target folder globally for the whole project.
Since there is no Visual Studio support for that, you have to add this property to the csproj-File manually:
<MTargetFolder>Repository/Wbs</MTargetFolder>
You will also have to create the folder along with the repository every time you deploy, using the following command:
mx createFolder "Repository/Wbs" /database:WbsTestRepository /server:.\SQLExpress
The next thing is some complaints about my constraints on TaskEstimate. Since I have no time left, and those constraints should be weak, instead of hard CHECK constraints anyway, I’ll just comment them "away” for now.
Deployed successfully.
Wonderful. Now lets go to “Quadrant” and see, how we can make use of the model with it’s sample data.
Summary
It were not really the syntax changes that made trouble, but rather the integration with Visual Studio. I had a couple of simple customizations for Quadrant, but I’ll rewrite them soon.
The only comment I have to make so far, is, that it is totally unacceptable to have a development cycle that takes more than 5 seconds from M over compile, deploy and look at the changes in Quadrant. Now it takes more than 30 seconds.
Future Plans
I’ll probably elaborate more on WBS next week. I’ll also migrate my DSL pet project called “Web Layout DSL” and integrate it with a MVC Client Application over WBS.
So stay tuned.