views:

38

answers:

1

Hi,

I'm hoping somebody can help me with this, I'm trying to write the mapping classes for a class that is subclassed into a generic class. Its easier to descibe with code, so here is my model...

public abstract class TagBase
{
    public virtual int Id { get; private set; }
    public virtual TagTypeEnum TagType { get; set; }
    public virtual string Value { get; set; }
    public virtual bool IsSystemTag { get; private set; }
    public virtual bool isDeleted { get; set; }

    public TagBase()
    {
    }

    public TagBase(TagTypeEnum tagType)
    {
        this.TagType = tagType;
    }

    public override string ToString()
    {
        return Value;
    }
}

public class Tag<TLinkedItem> : TagBase where TLinkedItem : ITagged<TLinkedItem>
{
    public virtual List<TLinkedItem> LinkedItems { get; set; }
}

As you can see Tag is generic but is constrained to only those classes that implement ITagged<T>

The idea is that an entity has Tags and in turn a tag has a list of LinkedItems that are strongly typed.

Tags cannot be shared amongst different types of entity

I only have two entities in my model that support tagging so far thay are Display and Asset

I've tried to map this with the following Fluent NHibernate code;

public class TagBaseMap : ClassMap<TagBase>
{
    public TagBaseMap()
    {
        Table("Tag");
        Id(tag => tag.Id);
        Map(tag => tag.Value).Not.Nullable().Length(50);
        Map(tag => tag.IsSystemTag).Not.Nullable();
        Map(tag => tag.isDeleted).Not.Nullable();
        Map(tag => tag.TagType).CustomType<Int32>().Not.Nullable();
    }
}

public class DisplayTagMap : SubclassMap<Tag<Display>>
{
    public DisplayTagMap()
    {
        HasManyToMany(displayTag => displayTag.LinkedItems).Inverse().Table("DisplayTagLink");
    }
}

public class AssetTagMap : SubclassMap<Tag<Asset>>
{
    public AssetTagMap()
    {
        HasManyToMany(assetTag => assetTag.LinkedItems).Inverse().Table("AssetTagLink");
    }
}

When I try and build the database, I'm targetting Sql Server, from this mapping I'm getting this error "Incorrect syntax near '`'."

Am I right in thinking caused by .Net's naming of generic classes ie,

'{[Model.Tag'1[[Model.Asset, Model, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].LinkedItems, NHibernate.Mapping.Bag(Model.Tag'1[[Model.Asset, Saturn.ConnectVision.Model, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].LinkedItems)]}'

Am I doing something daft here?

Is there a way around this problem?

Thanks in advance for any advice.

A: 

OK, I seemed to have worked around this problem for now.

Here is the mapping for the generic versions of Tag where T : ITagged

public class DisplayTagMap : SubclassMap<Tag<Display>>
{
    public DisplayTagMap()
    {
       HasManyToMany(displayTag => displayTag.LinkedItems).Inverse().Table("DisplayTagLink").ParentKeyColumn("display_id").ChildKeyColumn("tag_id");
    }
}

public class AssetTagMap : SubclassMap<Tag<Asset>>
{
    public AssetTagMap()
    {
        HasManyToMany(assetTag => assetTag.LinkedItems).Inverse().Table("AssetTagLink").ParentKeyColumn("asset_id").ChildKeyColumn("tag_id");
    }
}

So I'm overriding the generated column names that cause illegal Sql syntax, of course there is the reverse mapping to consider.

    public class DisplayMap : ClassMap<Display>
{
    public DisplayMap()
    {
        Id(display => display.Id);
        Map(display => display.Name).Not.Nullable();
        Map(display => display.DisplayGUID).Not.Nullable();
        Map(display => display.Description);
        HasManyToMany(display => display.Tags).Cascade.All().Table("DisplayTagLink").ParentKeyColumn("display_id").ChildKeyColumn("tag_id");
    }
}

The only issue I now have is that if I put in a DiscriminateSubclassesOnColumn("TagType") I get the same syntax issue creeping in.

If I miss out this declaration, I end up with two additional tables, Tag_Asset and Tag_Display that just contain a foreign key back to Tag. This is not such a big deal for now.

I've avoided DiscriminateSubClassOnColumn("TagType").SubClass<Tag<Display>>(..... because this will cause me to have to modify this declaration for each subclass that I add.

Andy Baker