Minor update to WORM CodeSmith templates

I just made a small update to the CodeSmith templates for Wilson’s O/R Mapper:

11/30/06: The default constructor for the EntityBase class now calls a virtual method, Initialize(). By overriding the Initialize() method in your partial class, you can ensure code will run every time your entity is instantiated. This is useful as it avoids the need to override the base constructor in the generated partial class file, which would be overwritten by the code generation process.

For more details and to download the templates, go to CodeSmith Templates for Wilson’s O/R Mapper.

New CodeSmith templates for Wilson’s O/R Mapper

Last week, I wrote about a new version of CodeSmith templates for Paul Wilson’s O/R mapper that I’ve been working on. After fixing a few bugs and including some very simple unit tests, I’m pleased to announce the first public release!

Some important notes on this release:

  • The templates are written for CodeSmith version 4.0.
  • The templates are based heavily on Paul Welter’s templates, and most of the low-level code is the same as the code used in his templates. As a result, if you’re familiar with his templates, it shouldn’t be hard to get used to these.
  • The unit tests included are very basic but provide a starting point.

Instructions and download links are available in the Articles section of my web site under Projects: CodeSmith Templates for Wilson’s O/R Mapper.

Compiled version of ASP.Net CSSFriendly Control Adapters (RTM 1.0)

Last week, I released a compiled version of Microsoft’s CSSFriendly ASP.Net 2.0 Control Adapters (“CSSFriendly”). Since that post, the “1.0” RTM version of the adapters were released. I just finished porting the latest release to a compiled assembly.

Instructions for installing and using the compiled adapters, and download links, can be found in the Projects section of this web site.

Compiled version of ASP.Net CSSAdapters (Beta 3.0)

UPDATE 11/24/06: The 1.0 version of the adapters was released, so I updated the compiled distribution. Read about the update here.

UPDATE: Added a link to download just the DLL at the bottom of the entry, and rewrote some of the “implementation” steps to make them a bit clearer.

I’ve been following the progress of the CSSFriendly ASP.Net 2.0 Control Adapters (“CSSAdapters”) since they were initially launched some 6+ months ago. The team has continually worked on revising them (with a little help from me), and the latest release (Beta 3.0) seems to be something that we can live and work with comfortably.

One thing I’ve hated about the adapters is the implementation, which basically involves the following steps:

  1. Add a file to the App_Browsers directory.
  2. Add a folder of JavaScript files.
  3. Add a folder of CSS files.
  4. Add a bunch of files to the App_Code directory
  5. Add some tags to the section of your web pages (to import the stylesheets and handle some conditional imports for IE6 and IE7).

Apparently, I’m not the only person who thinks there should be an easier way, and it seems that the folks working on the CSSAdapters agree (see the Serving Suggestions topic on the ASP.Net forums).

Inspired by the posts in that topic (especially the post by HardyE), I present to you a fully-compiled version of the CSSAdapters (Beta 3.0). A few notes on the implementation follow.

  • All the CSS and JavaScript files are now embedded resources — no more files to manage; everything is in one DLL.
  • The only CSS files embedded are those that actually do anything. In other words, I removed all but the following: DetailsView.css, Menu.css, TreeView.css, IEMenu6.css, and IEMenu7.css.
  • To get the JavaScript files to register (required for the MenuAdapter, TreeViewAdapter, and all controls that use the WebControlAdapterExtender), I rewrote the RegisterScripts() method to reference the JavaScript file as a Web resource (using GetWebResourceUrl()). I also added a check to IsClientScriptIncludeRegistered() which should make sure things are only added once.
  • To get the CSS files to link (required for the MenuAdapter, TreeViewAdapter, and DetailsViewAdapter), I added code to the RegisterScripts() method to reference the CSS file as a Web resource (using GetWebResourceUrl()). Adding them to the web page was done by parsing a tag and adding it to the page using RegisterClientScriptBlock(). As with JavaScripts, I also added a check to IsClientScriptBlockRegistered() to avoid duplication.

Implementation of the compiled CSSAdapters in a web site requires the following steps. Note that only the first step is the same as those listed above; steps #2 through #5 are eliminated by the “new” step #2 below.

  1. Add the appropriate file to your App_Browsers directory (this step doesn’t go away, and it shouldn’t, because essentially this is a configuration file).
  2. Add the compiled CSSAdapters.dll to your web site’s bin directory.

This makes it much easier to implement and manage than before. Note that this implementation wasn’t heavily tested, but it worked flawlessly with the CSSAdapters demo app (which is included in the distribution I’m providing here). Let me know how it works for you, or if you have any problems or suggestions.

For instructions and download links, go to the Projects section of this web site.

New (kind of) CodeSmith templates for Wilson’s O/R Mapper

I’ve been using Paul Wilson‘s excellent O/R mapper for a while now, and I’ve become so enamored by it that every project I’ve worked on in the past six months have used it. (All projects are web sites.) Wilson’s O/R Mapper (WORM for short), combined with Paul Welter‘s excellent CodeSmith templates, saved me many hours of coding and provided excellent functionality — well worth the $50 (for WORM) and $99 (for CodeSmith).

One thing that I often wanted to break away from is the ActiveRecord model used in Welter’s templates — not because it’s wrong (ActiveRecord is a very solid, easy-to-use pattern), but because I wanted more. Specifically, I wanted to separate my business objects from my data access code.

Over the past two weeks, while working on the next version of my online baseball game, CSFBL, I started hacking apart the code generated by Welter’s templates, to the point where I separated the data classes from the data access code. I then upgraded to CodeSmith 4.0 Professional and rewrote the templates to generate code based on my “new” way of doing things.

As of now, the templates generate code that compiles and does what it supposed to — however, before releasing it I want to test it a little more and perhaps write a few unit tests. Maybe even redo Welter’s unit test generator, too, to work with the modified templates. 😉

These modified CodeSmith templates generate two projects: one for your entity objects, and one for your data access objects. The templates (written using CodeSmith 4.0, but will probably work in 3.2 — I’ll test it before publishing) are for .Net 2.0 only, as they make heavy use of generics.

How the Entity layer works

Each table gets a class using the same partial class and generated file technique we know and love. Each of these classes inherit from one or more of the following classes: EntityBase or PersistableEntity.

  • EntityBase is the base class for all entity objects. Its main purpose is in exposing three interfaces, IComparable, IComparable, and IEquatable, and defining methods where appropriate. The goal of an EntityBase is to provide a few core features, chief among them being an implementation of CompareTo() and Equals() methods that check for equality based on primary keys. The base provides plumbing for the generated classes to do this reliably.
  • PersistableEntity inherits from EntityBase and implements the IPersistable interface. Essentially, a read-only table (as defined in the Mappings.config) would inherit from EntityBase, and all other objects would inherit from PersistableEntity. The IPersistable interface defines methods to track the state (“dirty” and “deleted”) of the object, and nothing more. ** Note that the implementation of this isn’t fully done in that the states aren’t used effectively yet. This was a last-minute change I made so it’s not complete. **

The actual generated class would inherit from either EntityBase or PersistableEntity. Implementing the IObjectHelper interface is an option in the CodeSmith template (if you don’t implement it, your entity library will not need to reference WORM at all). The generated code creates fields and properties as you would expect. It also does the following:

  • Creates a strongly-typed CompareTo() method that will compare every key field.
  • Creates a strongly-typed Equals() method that will compare every key field.
  • Overrides GetHashCode() to generate a hash code based on primary key fields (currently it’ll only work with numeric fields, but that’ll be fixed soon).
  • Overrides ToString() to generate output that presents each primary key separated by a colon.

Finally, the generated code has a second class in it that inherits from a new IIdentity interface. This simple class is used by the Data Access classes for “RetrieveByKey” and “DeleteByKey” methods (see below for details).

How the Data Acess layer works

The DAL is not as much a DAL as it is a gateway between the entities and the O/R mapper, but since I’m no master of the right architecture pattern names to describe a situation, I’ll leave it named as such. After code generation this project will have five files.

  • A reference to the mappings file (i.e. Mappings.config). Note that the DAL needs to have this file embedded, not the entity layer.
  • A TransactionManager static class, which is basically a stripped-down version of the similar-named class from Welter’s templates. (I just removed what wouldn’t work, not much else changed in this.)
  • An updated DataManager static class. This expands on what was in Welter’s templates.
    • It allows you to define a providerName in your connectionStrings section that will automatically define the appropriate ObjectSpace, including support for the .Net built-in SqlClient, Odbc, OleDb, and OracleClient, as well as the WilsonXmlDbClient (via a custom provider). Note that I’ve only tested the SqlClient and the WilsonXmlDbClient.
    • It allows you to automatically integrate NLog as an interceptor to trace the SQL generated by WORM. The option to do this is in the template. It uses some various techniques I found around the web.
    • It implements a technique to cache the IsolatedContext in web environments by using HttpContext (a technique illustrated by David Neal at www.ChristianASP.NET.
  • A new Retrieve static class that provides all the data retrieval methods. The Retrieve class provides the expected Retrieve methods, like RetrieveAll() and RetrieveQuery() — essentially all the Retrieve() methods that used to be in Welter’s templates.
  • A new Persist static class that provides all the data persistence methods. This class inherits from Retrieve (mostly to share the functionality of one method, but also for convenience) and provides all the data persistence methods — Save, Delete, and so-forth. This class requires that T is of type IPersistable.
  • Previously I mentioned the IIdentity interface. This is used by the RetrieveByKey and DeleteByKey methods and allows us to maintain generic data access classes while being able to use strongly-typed keys as well.

    An example of how the data layer works is shown below. The examples assume entity classes exists called Teacher, whose primary key is TeacherID.

    //retrieve a Teacher
    Teacher teacher = Retrieve<teacher>.RetrieveFirst();
    
    //retrieve all Teachers
    IList</teacher><teacher> teachers = Retrieve</teacher><teacher>.RetrieveAll();
    
    //retrieve a teacher whose primary key is 74
    TeacherIdentity tid = new TeacherIdentity(74);
    Teacher teacher = Retrieve</teacher><teacher>.RetrieveByKey(tid);
    
    //you could also write the above in one line:
    Teacher teacher = Retrieve</teacher><teacher>.RetrieveByKey(new TeacherIdentity(74));
    
    //saving changes to a teacher
    teacher.Name = "Dr. Spock";
    Persist</teacher><teacher>.Save(teacher);
    
    //deleting a teacher
    Persist</teacher><teacher>.Delete(teacher);
    
    //deleting a teacher whose primary key is 74
    Persist</teacher><teacher>.DeleteByKey(new TeacherIdentity(74));
    
    //creating a new teacher record will not be tracked by WORM
    //this is perfectly valid
    Teacher teacher = new Teacher();
    
    //you can start tracking by calling the Track() method
    Persist</teacher><teacher>.Track(teacher);
    
    //you can also instantiate a new teacher with tracking
    Teacher teacher = Persist</teacher><teacher>.New();
    

    The unit tests I wrote pretty much did what you see above.

    I will hopefully release the actual templates in a few days, once I do some more testing on them and clean up some of the output formatting a bit. In the meantime, feel free to let me know what you think!

    On disk space and defragmentation

    My online baseball game, CSFBL, is a data hog to the tune of about 100GB. Yes, 100GB. That’s how much disk space it takes to store the play-by-play results of some 5 million baseball games (over 2,500 seasons) along with the related player data, historical statisics, and other fun stuff.

    The server that powers this beast has three 146GB SCSI drives in a RAID5 configuration. That’s about 250GB of available disk space. Excluding data requirements for such necessities like Windows, SQL Server, tempdb files, web files, and the like, we typically have between 50GB and 100GB of free disk space.

    Of course, backing up that database is another story entirely, and if I’m not diligent in keeping the disk clean (by deleting old and unneeded data files), the server can quickly run out of space. This has happened from time to time over the past few years, but a quick cleanup resolves the issue.

    Over the weekend I decided to take on major maintenance, defragmenting all SQL indexes, cleaning up old data, removing unused applications, and similar fun weekend chores. During this, I checked the level of fragmentation on the SQL database file.

    Over 40,000 file fragments.

    Whoa! How long does it take to defragment that? About two days. Of course, a lot of that time was spent first defragmenting other files to make room for one big file. The built-in Windows defragger didn’t do the trick at all (it fails miserably unless you have gobs of free disk space or no large files to defragment). What did do the trick was an evaluation version of Raxco‘s PerfectDisk. Fortunately for my wallet, the eval version is full-featured for 30 days, and since my defrag needs are done, I don’t have to buy it — at least, not until I have to defrag the database again.

    Then again, I’m planning ahead this time. I set the SQL database to have about 30GB of free space, so the only fragmentation should be internal, not external. By the time I need to worry about a fragmented SQL data file again, there will be another 1.5 million baseball games simulated, and hopefully a little more ad revenue coming in. 😉