Reputation: 4495
I am implementing a custom form designer. I'm now to the point where I want to persist the layout to the database.
Here is a design I have come up with:
public class Control
{
public virtual int Id { get; set; }
public virtual string Type { get; set; }
public virtual Dictionary<string, string> Properties { get; set; }
}
I would then map this so I could do something like this to reload the layout:
var controls = GetListOfControlsUsingNHibernate();
foreach (var control in controls){
var newControl = CreateControlFromType(control.Type);
SetPropertiesViaTypeDescriptor(newControl, control.Properties);
this.Controls.Add(newControl);
}
I have two questions.
Upvotes: 1
Views: 883
Reputation: 4495
A bud on twitter pointed me in the right direction for mapping this using Fluent NHibernate:
First create a table named Properties
to hold our properties:
╔═══════════╦══════════════╦═══════════════╗
║ ControlId ║ PropertyName ║ PropertyValue ║
╚═══════════╩══════════════╩═══════════════╝
Now change our mapping like this:
public class ControlMap : ClassMap<Control>
{
public ControlMap()
{
Table("Controls");
Id(x => x.Id);
Map(x => x.Type);
HasMany(x => x.Properties).Table("ControlProperties")
.AsMap<string>(index => index.Column("PropertyName").Type<string>(),
element => element.Column("PropertyValue").Type<string>())
.Cascade.All();
}
}
For some background on the hbm xml behind this see Ayende's NHibernate Mapping Map.
Upvotes: 0
Reputation: 1928
Some alternative ways to do that.
One solution is to use inheritance
public abstract class Control
{
// ...
}
public class TextBox : Control
{
public virtual string Text { get; set; }
}
public class MaskedTextBox : TextBox
{
public virtual string Mask { get; set; }
}
Another is to use different kinds of properties
public class Control
{
public virtual ISet<Property> Properties { get; set; }
}
public abstract class Property
{
public virtual string Name { get; set; }
}
public class IntProperty : Property
{
public virtual int Value { get; set; }
}
public class DecimalProperty : Property
{
public virtual decimal Value { get; set; }
}
// ...
Yet another is to use interfaces
public abstract class Control
{
}
public class TextBox : Control, ITextControl
{
public virtual string Text { get; set; }
}
public class ConcreteControlMap<T> : SubclassMap<T> where T : Control
{
public ConcreteControlMap()
{
if(typeof(ITextControl).IsAssignableFrom(typeof(T)))
{
Map(c => ((ITextControl)c).Text);
}
}
}
Upvotes: 1