Operator overloading your domain model with interfaces and base classes

One of the challenges in rewriting my online baseball game is dealing with enormous amounts of data that needs to be stored as aggregates, and coming up with a domain model and data mapping pattern that works. In this blog post, I’ll outline how I addressed some of those issues.

The Data Model

Baseball is very much a statistics-oriented game. Consider fielding statistics: putouts (PO), assists (A), errors (E) and others. These stats need to be stored:

  • Per game, for each player who played in the game, for each position he played (key fields: game, player, position)
  • Per season, for each player, for each team he played for, for each position he played (key fields: season, player, team, position)
  • Career, for each player, for each position he played (key fields: player, position)

On the database side, that results in three tables: GameFieldingStats, SeasonFieldingStats, and CareerFieldingStats. Each has the same set of fields to store the statistics (PO, A, and E); the differences are in the key fields for each, as outlined in the diagram below. (Note: For the remainder of this post, I’ll include only the first two of those tables to keep things short.)

Continue reading

Assess your .Net skills (and get a job) with this online test

Brant Estes of Magenic Technologies has just posted a very nice online quiz for .Net programmers. The test is there to pre-screen potential candidates to work at Magenic, but it’s also a very nice test for any .Net programmer to take (or to give to any .Net programmer you have considered hiring).

My Magenic Technologies .Net test scoreI took the test and scored a 75 out of 100 (without cheating, mind you), and was told I may make a great addition to Magenic. Unfortunately, I live in New York, and I’m not relocating. Besides, I just put in my resignation with my current employer so I can go back to independent consulting, so I’m not exactly on the market for full-time employment… but more on that another day.

A simple asp:Repeater replacement for simple needs

How many times have you had to parse through a collection of objects, outputting nothing more than a comma-delimited list of items in the result set. Typically, you’ll do this:

<asp :repeater runat="server">
	<itemtemplate>Eval("Name")</itemtemplate>
	<separatortemplate>, </separatortemplate>
</asp>

If you were parsing a list of states, it might look like this:

Alabama, Alaska, Arizona, Arkansas

There’s an easier way to handle these simple needs: create a CollectionToString() method. This method would accept an IEnumerable and, using reflection, read a property and return a delimited string. Of course, you choose the property and delimiter.

Note that we have two versions of this method: one which accepts an IEnumerable, the other which accepts an object. This is done to avoid the necessary typecasting in your code, since Eval() returns everything as an object.

public static string CollectionToString(IEnumerable collection, string property, string delimiter)
{
	IEnumerator enumerator = collection.GetEnumerator();
	if (enumerator == null || enumerator.MoveNext() == false)
		return String.Empty;

	Type type = enumerator.Current.GetType();
	PropertyInfo propInfo = type.GetProperty(property);
	if (propInfo == null)
		throw new Exception(String.Format("Property '{0}' not found in collection", property));

	StringBuilder output = new StringBuilder();
	output.Append(propInfo.GetValue(enumerator.Current, null).ToString());

	while (enumerator.MoveNext())
	{
		output.Append(delimiter);
		output.Append(propInfo.GetValue(enumerator.Current, null).ToString());
	}

	return output.ToString();
}

public static string CollectionToString(object collection, string property, string delimiter)
{
	return CollectionToString(collection as IEnumerable, property, delimiter);
}

This method — which I typically apply to a StringHelper class whose namespace is added to my web.config (more on that another day) — can replace the Repeater code above as follows.

<!-- you must first expose the collection to the ASPX page as a public property -->
< %= StringHelper.CollectionToString("ListOfStates", "Name", ", ") %>

A similar method could be added to a helper class in Castle MonoRail to do the same without using foreach loops in your view.

A repository that works with multiple O/R mappers — is it possible?

A recent post on the WilsonORWrapper Google group talked about making WORW multi-database aware by removing static classes and singletons. Well, I’ve kind of been thinking of something similar lately…

For some time I have been toying with the idea of rewriting WORW to support a generic repository service that would work with any O/R mapper, much
like the logger and cache services work over different underlying libraries. By removing the static classes and singletons and adding a provider model for the O/R wrapper element, you would be able to instantiate multiple instances of a “Registry” class, a class which provides a set of services (Repository, Cache, Logger, etc.) based on a given configuration criteira.

As a test I wrote up a simple project (with unit tests!) as a proof-of-concept, using WORM and NPersist as underlying O/R mappers. The WORM part worked fine. The NPersist part almost worked — however, I believe the errors are related to using NPersist’s not-too-well-documented XML provider, not errors with the O/R mapper provider itself (NPersist does initializes properly, which indicates at least something is working right).

If you’re interested in seeing this little stub of a project, download the source (27.5kb). I’ve dubbed it NRepository right now, not for any reason except it’s the first thing that came to mind. Let me know what you think, and whether you think it’s worth pursuing such a project.

Use reflection to compare the properties of two objects

In an update to WilsonORWrapper, I added a method which takes two objects of the same type and compares the properties of each, returning a value reflecting the results of the comparison. Any value other than zero would indicate that at least one property on the objects are not equal.

This method may have interest to people who don’t use WilsonORWrapper, so here’s an extracted version of the code that does the comparison.

using System;
using System.Reflection;

public static class ObjectHelper<t>
{
	public static int Compare(T x, T y)
	{
		Type type = typeof(T);
		PropertyInfo[] properties = type.GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public);
		FieldInfo[] fields = type.GetFields(BindingFlags.DeclaredOnly | BindingFlags.Public);
		int compareValue = 0;

		foreach (PropertyInfo property in properties)
		{
			IComparable valx = property.GetValue(x, null) as IComparable;
			if (valx == null)
				continue;
			object valy = property.GetValue(y, null);
			compareValue = valx.CompareTo(valy);
			if (compareValue != 0)
				return compareValue;
		}
		foreach (FieldInfo field in fields)
		{
			IComparable valx = field.GetValue(x) as IComparable;
			if (valx == null)
				continue;
			object valy = field.GetValue(y);
			compareValue = valx.CompareTo(valy);
			if (compareValue != 0)
				return compareValue;
		}

		return compareValue;
	}
}

With that, if you had a Name class in your code that had two properties, First and Last, you could do something like this:

Name n1 = new Name();
n1.First = "Brian";
n1.Last = "DeMarzo";

Name n2 = new Name();
n2.First = "Brian";
n2.Last = "DeMarzo";

int result1 = ObjectHelper<name>.Compare(n1, n2);
// result1 == 0 because n1 and n2 have equal properties

n1.First = "Alyssa";
// change the first name, so n1 should no longer equal n2

int result2 = ObjectHelper</name><name>.Compare(n1, n2);
// result2 != 0 because n1 and n2 do not have equal properties

Code like this came in handy in my project where I use FileHelpers (see my blog entry from earlier today), where I was able to compare a class loaded from the database (using an O/R mapper) with a class loaded from a text file (using FileHelpers). Since the O/R mapper and FileHelpers used the same class, using this comparison method to determine if the objects were “equal” let me determine whether or not the data loaded from the database was different from the data in the text file.

Even though it used reflection, there wasn’t a huge performance hit, either. Sure beats writing manual comparison methods, which could take a while when you have a few dozen classes!

Simplify configuration with a generic ConfigurationElementCollection class

I’ve been using Phil Haack‘s Custom Configuration Sections in 3 Easy Steps for some time now, and my configuration file management has never been happier… until I needed to read a collection of configuration elements.

Here’s a sample of the XML I needed to incorporate:

<importer>
	<filespecs>
		<add type="EmployeeCSV" path="d:\import\employees.csv" />
		<add type="OrderCSV" path="d:\import\orders_*.csv" />
	</filespecs>   
</importer>

The typical solution is to write your own collection class (FilespecConfigurationElementCollection), inheriting from ConfigurationElementCollection, and ensuring your Filespec object inherits from ConfigurationElement. I figured there has to be a better way — and there is.

I wrote a generic version of ConfigurationElementCollection, which you can use to avoid writing the custom collection class. The code that follows is the generic class, the Filespec object I used, and the property declaration from my ConfigurationSettings class (as described in Phil’s previously mentioned article).

Note one key part of this implementation: You must override the ToString() method of your custom ConfigurationElement class to return a unique value. The generic ConfigurationElementCollection uses the ToString() method to obtain a unique key for each element in the collection.

// The ConfigurationElementCollection<t> provides a simple generic implementation of ConfigurationElementCollection.
[ConfigurationCollection(typeof(ConfigurationElement))]
public class ConfigurationElementCollection</t><t> : ConfigurationElementCollection where T : ConfigurationElement, new()
{
	protected override ConfigurationElement CreateNewElement()
	{
		return new T();
	}
	protected override object GetElementKey(ConfigurationElement element)
	{
		return ((T)(element)).ToString();
	}
	public T this[int idx]
	{
		get { return (T)BaseGet(idx); }
	}
}
// The Filespec class is an example of a custom configuration element.
// Note that we inherit from ConfigurationElement, and use ConfigurationProperty attributes.
public class Filespec : ConfigurationElement
{
	public Filespec()
	{
	}
	[ConfigurationProperty("path", DefaultValue="", IsKey=true, IsRequired=true)]
	public string Path
	{
		get { return (string)(base["path"]); }
		set { base["path"] = value; }
	}
	[ConfigurationProperty("type", IsKey=false, IsRequired = true)]
	public FilespecType Type
	{
		get { return (FilespecType)(base["type"]); }
		set { base["type"] = value; }
	}

	public override string ToString()
	{
		return this.Path;
	}
}
// Finally, our ConfigurationSettings class (only part of the class is included).
// Note how we use the generic ConfigurationElementCollection.
public class ConfigurationSettings : ConfigurationSection
{
// ...
	[ConfigurationProperty("filespecs", IsRequired=true)]
	public ConfigurationElementCollection<filespec> FileSpecs
	{
		get { return (ConfigurationElementCollection</filespec><filespec>)this["filespecs"]; }
	}
// ...
}

If you’re using a number of ConfigurationElementCollections, this is a great way to simplify your code.

Article to appear in September 2004 DNDJ

I received word that my third article for .Net Developer’s Journal will appear in the September 2004 issue. It’s the third in the series of articles entitled, “C# and the .Net Framework: Tying It All Together”. The first article was in the January 2004 issue, the second article was in the May 2004 issue. Why such a delay between articles? They never told me they were publishing the first article, so I didn’t get the second article to them until after it printed. They never received the third article (which was originally sent in May 2004) and we didn’t catch up with each other until last month. I’m working on the fourth article now and hopefully it’ll be in the October or November issue.