Question

I have the following:

public abstract class FooBase
{
    public virtual int Id { get; set; }
}

public class Foo1 : FooBase { /* could be stuff here */ }

public class Foo2 : FooBase { /* could be stuff here */ }

public class Bar
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual SOMETHING WhichFoo { get; set } 
}

...where WhichFoo deals with which FooBase to use (potentially string of "Foo1" but this seems quite messy).

With mappings:

public class FooBaseMap : ClassMap<FooBase>
{
    public FooBaseMap()
    {
        this.Id(x => x.Id);
        this.DiscriminateSubClassesOnColumn("Type");
    }
}

public class Foo1Map : SubclassMap<Foo1>
{
    public Foo1Map() { this.DiscriminatorValue("Foo1"); }
}

public class Foo2Map : SubclassMap<Foo2>
{
    public Foo2Map() { this.DiscriminatorValue("Foo2"); }
}

What I want to be able to do is to create a new Foo, either 1 or 2, based on a value stored in Bar. So:

Bar bar = this.Session.Get<Bar>(1);

FooBase foo1 = bar.GetANewFoo(); // returns a new Foo1

Bar anotherBar = this.Session.Get<Bar>(123);

FooBase foo2 = bar.GetANewFoo(); // returns a new Foo2

Where GetANewFoo() could be a method, a property which returns an empty instance of Foo1 or Foo2.

Effectively what I want to do is to store the type of FooBase to be created by GetANewFoo in Bar.

What's the best way of going about this without explicitly having to manually write "Foo1" or "Foo2" to a Bar when I create one?

Was it helpful?

Solution 2

Okay I think I got it - actually rehashing a method I used for the Strategy Pattern.

public abstract class FooFactoryBase
{
    protected FooFactoryBase() { } // for NHibernate

    protected FooFactoryBase(Guid id)
    {
        this.Id = id;
    }

    public virtual Guid Id { get; set; }
    public virtual IList<Bar> Bars { get; set; }
    public abstract FooBase CreateFoo();
}

public class Foo1Factory : FooFactoryBase
{
    public readonly static Guid Guid = new Guid("abc123...");

    public Foo1Factory() : base(Guid) { }

    public override FooBase CreateFoo()
    {
        return new Foo1();
    }
}

Then Bar becomes:

public class Bar
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual FooFactoryBase FooFactory { get; set; }
}

And mappings:

public class BarMap : ClassMap<Bar>
{
    this.Id(x => x.Id);
    this.Map(x => x.Name);
    this.References(x => x.FooFactory);
}

public class FooFactoryBaseMap : ClassMap<FooFactoryBase>
{
    this.Id(x => x.Id);
    this.HasMany(x => x.Bars).Inverse();
    this.DiscriminateSubClassesOnColumn("Id");
}

public class Foo1FactoryMap : SubClassMap<Foo1Factory>
{
    this.DiscriminatorValue(Foo1Factory.Guid);
}

Now when I create my database I can populate it with all my FooFactorys, when adding Bars I can just load the appropriate Factory from the database and then call my code like so:

Bar bar = this.Session.Get<Bar>(10);

FooBase foo = bar.FooFactory.CreateFoo();

and the appropriate FooBase will be created.

Sometimes you just need to ask the question to figure it out :)

OTHER TIPS

You can create a column in the Bar table which is going to save what kind of Foo it is. So, if this SOMETHING type of property is an enum, or a string, or an int (whatever), you can use switch-case statement to identify the kind of Foo, create what you need and return.

Just like this:

    public FooBase GetANewFoo()
    {
        switch (WhichFoo)
        {
            case "Foo1": return new Foo1();
            case "Foo2": return new Foo2();
            default: return null;
        }
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top