string
is an alias in C# for System.String
.
So technically, there is no difference. It's like int
vs. System.Int32
.
As far as guidelines, it's generally recommended to use string
any time you're referring to an object.
e.g.
string place = "world";
Likewise, I think it's generally recommended to use String
if you need to refer specifically to the class.
e.g.
string greet = String.Format("Hello {0}!", place);
This is the style that Microsoft tends to use in their examples.
It appears that the guidance in this area may have changed, as StyleCop now enforces the use of the C# specific aliases.
I figured it out in case of enums.
Considering this enum type:
public enum ActivityType
{
[EnumKey("1")]
[EnumDescription("ImportFromFile")]
ImportFromFile,
}
where EnumKey and EnumDescription are (popular) extension methods, I redefine Activity like
public abstract class Activity
{
public virtual Guid Id { get; set; }
public virtual ActivityExecutionResult ExecutionResult { get; private set; }
public virtual ActivityExecutionStatus ExecutionStatus {get;private set;}
public abstract ActivityExecutionStatus Execute();
public virtual string ActivityName { get; private set; }
public virtual IDictionary<string, string> ActivityParameters { get; private set; }
public virtual ActivityType ActivityType { get; private set; }
}
The mapping file looks like this:
public class ActivityMap : ClassMap<Activity>
{
public ActivityMap()
{
Table("Activities");
Id(x => x.Id).Column("ID").GeneratedBy.Guid();
Map(x => x.ActivityName).Not.Nullable().Length(50);
Map(x => x.ActivityType).CustomType<int>().Column("ActivityType").Not.Nullable();
HasMany(x => x.ActivityParameters)
.KeyColumn("ActivityID")
.AsMap<string>(idx => idx.Column("ParameterName"), elem => elem.Column("ParameterValue"))
.Not.LazyLoad()
.Cascade.Delete()
.Table("ActivityParameters");
DiscriminateSubClassesOnColumn("ActivityType");
}
}
public class ImportActivityFromFileMap : SubclassMap<ImportActivityFromFile>
{
public ImportActivityFromFileMap()
{
DiscriminatorValue(ActivityType.ImportFromFile.GetKey());
}
}
The generated hbm file looks like:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="property" auto-import="true" default-cascade="none" default-lazy="true">
<class xmlns="urn:nhibernate-mapping-2.2" name="***.Activity, ***, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="Activities">
<id name="Id" type="System.Guid, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="ID" />
<generator class="guid" />
</id>
<discriminator column="ActivityType" type="String" insert="true" not-null="true" />
<property name="ActivityName" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="ActivityName" length="50" not-null="true" />
</property>
<property name="ActivityType" type="Int32">
<column name="ActivityType" not-null="true" />
</property>
<map cascade="delete" lazy="false" name="ActivityParameters" table="ActivityParameters">
<key>
<column name="ActivityID" />
</key>
<index type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="ParameterName" />
</index>
<element type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="ParameterValue" />
</element>
</map>
<subclass name="***.ImportActivityFromFile, ***, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" discriminator-value="1" />
</class>
</hibernate-mapping>
It works like a charm!
Best Answer
I have found a workaround but this seems so like a patch... I added the following to the mapping file:
It seems to instruct FNH not to use a string (I think it uses the class name) for the abstract base class. To make it work with the -1 value, I also changed my discriminator type from byte to sbyte.
Edit: I missed that: this is the second parameter to DiscriminateSubClassesOnColumn that takes the default value. So the correct answer to my question is: