private Type CreateEntityType(TableDefinition tableDefinition)
		{
			var typeName = tableDefinition.GetEntityName();

			if (_types.ContainsKey(typeName) == false)
			{
				lock (_typeLocker)
				{
					if (_types.ContainsKey(typeName) == false)
					{
						var type = _entityTypeBuilder.Build(tableDefinition);

						_types.TryAdd(typeName, type);
					}
				}
			}

			return _types[typeName];
		}
		public Type Build(TableDefinition table)
		{
			var entityName = _dynamicAssembly.BuildAssemblyQualifiedTypeName(table.GetEntityName());

			var typeBuilder = _dynamicAssembly.CreateType(entityName);

			var identityProperties = new List<PropertyInfo>();

			foreach (var column in table.Columns)
			{
				var property = typeBuilder.DefineProperty(column.Name, column.Type);

				if (column.IsPrimaryKeyColumn)
				{
					identityProperties.Add(property);
				}
			}

			if (identityProperties.Any())
			{
				// TODO: i don't think these three methods should be extension methods...
				typeBuilder.DefineGetHashCodeMethod(identityProperties);

				var virtualEqualsMethod = typeBuilder.DefineVirtualEqualsMethod(identityProperties);

				typeBuilder.DefineOverrideEqualsMethod(virtualEqualsMethod, identityProperties);
			}
			else
			{
				throw new NotSupportedException(String.Format("No primary key columns found for table '{0}'.", entityName));
			}

			var newType = typeBuilder.CreateType();

			return newType;
		}
		public Type Build(TableDefinition table)
		{
			var mapName = _dynamicAssembly.BuildAssemblyQualifiedTypeName(table.GetMapName());

			var entityType = _dynamicAssembly.GetDynamicType(_dynamicAssembly.BuildAssemblyQualifiedTypeName(table.GetEntityName()));

			var baseClassType = OpenGenericClassMapType.MakeGenericType(entityType);
			var tableFunction = baseClassType.GetMethod("Table");

			var fullFuncType = OpenGenericFuncType.MakeGenericType(entityType, typeof (object));
			var filledExpressionType = OpenGenericExpressionType.MakeGenericType(fullFuncType);

			var lambdaExpressionFunction = OpenGenericLambdaFunction.MakeGenericMethod(fullFuncType);

			var compositeIdentityPartType = OpenGenericCompositeIdentityPartType.MakeGenericType(entityType);
			var keyPropertyMethod = compositeIdentityPartType.GetMethod("KeyProperty", new[] { filledExpressionType });

			var mapMethod = baseClassType.GetMethod("Map", new[] { filledExpressionType });

			var typeBuilder = _dynamicAssembly.CreateType(mapName, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.BeforeFieldInit, baseClassType);

			var constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, Type.EmptyTypes);

			var constructorIntermediateLanguageGenerator = constructorBuilder.GetILGenerator();

			var baseParameterlessConstructor = baseClassType.GetConstructor(Type.EmptyTypes);

			if (baseParameterlessConstructor == null)
			{
				throw new NullReferenceException(String.Format("Parameterless constructor not found for type '{0}'.", baseClassType));
			}

			constructorIntermediateLanguageGenerator.Emit(OpCodes.Ldarg_0);
			constructorIntermediateLanguageGenerator.Emit(OpCodes.Call, baseParameterlessConstructor);

			// TODO: save these LocalBuilders and use them below in calls to stloc??
			constructorIntermediateLanguageGenerator.DeclareLocal(typeof (ParameterExpression));
			constructorIntermediateLanguageGenerator.DeclareLocal(typeof (ParameterExpression));

			constructorIntermediateLanguageGenerator.Emit(OpCodes.Ldarg_0);
			constructorIntermediateLanguageGenerator.Emit(OpCodes.Ldstr, entityType.Name);
			constructorIntermediateLanguageGenerator.Emit(OpCodes.Call, tableFunction);

			constructorIntermediateLanguageGenerator.Emit(OpCodes.Nop);

			var identityColumns = new List<ColumnDefinition>();
			var regularColumns = new List<ColumnDefinition>();

			foreach (var columnDefinition in table.Columns)
			{
				if (columnDefinition.IsPrimaryKeyColumn)
				{
					identityColumns.Add(columnDefinition);
				}
				else
				{
					regularColumns.Add(columnDefinition);
				}
			}

			if (identityColumns.Count == 0)
			{
			}
			else if (identityColumns.Count == 1)
			{
				var column = identityColumns.Single();

				var idMethod = baseClassType.GetMethod("Id", new[] { filledExpressionType });

				DefineSingleColumnIdMapping(entityType, constructorIntermediateLanguageGenerator, column, idMethod, lambdaExpressionFunction);
			}
			else if (identityColumns.Count > 1)
			{
				var compositeIdMethod = baseClassType.GetMethod("CompositeId", Type.EmptyTypes);

				DefineMultipleColumnIdMapping(entityType, constructorIntermediateLanguageGenerator, identityColumns, compositeIdMethod, lambdaExpressionFunction, keyPropertyMethod);
			}

			foreach (var column in regularColumns)
			{
				DefineColumnMapping(entityType, constructorIntermediateLanguageGenerator, column, lambdaExpressionFunction, mapMethod);
			}

			constructorIntermediateLanguageGenerator.Emit(OpCodes.Ret);

			var newType = typeBuilder.CreateType();

			return newType;
		}