A colleague of mine has been trying to convince me to use NHibernate
in an upcoming project and, given the success he has had with it, it
is certainly a tempting prospect but, I am having some trouble trying
to see how I can make it fit given the requirements I have. I have
challenged him to try and come up with a way but I thought I'd also
ask you, given your extensive writings on the subject.
I've been tasked with coming up with a system that is suitably
componentised (!) so that we can resell independant functionality in a
building-block manner. Now I know this seldom works well but this is
what you get when the management team and the sales/marketing team are
the same people.
The below is an abridged (untested) version of what I've got in mind
so far -- it is a (anti?)pattern I have seen in some articles on game
programming and I think it might apply fairly well here:
public interface IComponent {
CompositeObject Container { get; set; }
}
public class CompositeObject {
private readonly Dictionary<Type, IComponent> components =
new Dictionary<Type, IComponent>();
public long ID { get; private set; }
public CompositeObject(params IComponent cc) {
for (int i = 0, len = cc.Length; i < len; i++)
AddComponent(cc[i]);
}
public void AddComponent<T>(T component) where T :
IComponent {
components[T] = component;
component.Container = this;
}
public T GetComponent<T>() where T : IComponent {
if (components.ContainsKey(typeof(T))) throw new
NotSupportedException();
return (T)components[typeof(T)];
}
public void LoadByID(long id) { /* implementation */ }
public void Save() { /* implementation */ }
}
public class PositionComponent : IComponent {
public float X { get; set; }
public float Y { get; set; }
}
public class ColorComponent : IComponent {
public float Red { get; set; }
public float Green { get; set; }
public float Blue { get; set; }
}
static class Program {
static void Main() {
CompositeObject pos = new CompositeObject(new
PositionComponent());
CompositeObject col = new CompositeObject(new
ColorComponent());
CompositeObject posCol = new CompositeObject(
new PositionComponent(),
new ColorComponent()
);
pos.LoadByID(1);
col.LoadByID(2);
posCol.LoadByID(3);
Console.WriteLine("pos.X = {0}",
pos.GetComponent<PositionComponent>().X);
Console.WriteLine("col.Red = {0}",
col.GetComponent<ColorComponent>().Red);
Console.WriteLine("posCol.X = {0}",
posCol.GetComponent<PositionComponent>().X);
Console.WriteLine("posCol.Red = {0}",
posCol.GetComponent<ColorComponent>().Red);
}
}
CREATE TABLE composite_objects (
oid UNIQUEIDENTIFIER DEFAULT CONVERT(UNIQUEIDENTIFIER,
CONVERT(BINARY(10), NEWID()) + CONVERT(BINARY(6), GETDATE())),
CONSTRAINT pk_composite_objects PRIMARY KEY (oid)
)
CREATE TABLE position_components (
oid UNIQUEIDENTIFIER,
x REAL,
y REAL,
CONSTRAINT pk_position_components PRIMARY KEY (oid),
CONSTRAINT fk_position_components_oid FOREIGN KEY (oid)
REFERENCES composite_objects (oid) ON DELETE CASCADE
)
CREATE TABLE color_components (
oid UNIQUEIDENTIFIER,
red REAL,
green REAL,
blue REAL,
CONSTRAINT pk_color_components PRIMARY KEY (oid),
CONSTRAINT fk_color_components_oid FOREIGN KEY (oid)
REFERENCES composite_objects (oid) ON DELETE CASCADE
)
The plan is to come up with the best way to load the required data
with a single SELECT statement and to save the data with as few INSERT/
UPDATE statements as possible. So far, the best I can come up with is
a "massive" sparse view of left joins that we tailor (or codegen)
based on the installed components, that hopefully is 'simple' enough
for the (unspecified) RDBMS to allow basic CRUD against e.g.:
CREATE VIEW composite_objects_view AS
SELECT oid, x, y, red, green, blue
FROM composite_objects co
LEFT JOIN position_components pc ON co.oid = pc.oid
LEFT JOIN color_components cc ON co.oid = cc.oid
But I'd rather not use such a sparse view, returning unnecessary NULL
fields and performing unnecessary left joins (especially as the number
of components increases) and it seems that NHibernate's mature inline
SQL generation would be very useful to avoid this, while maintaining a
single SQL statement principle, where possible.
Now, I was thinking I would code the concrete one-to-one mapping
between each IComponent implementation and the CompositeObject and
that maybe I could generate HQL or Criteria, based on the Types in the
components Dictionary but I can't help but feel I am just substituting
generation of one language for that of another. And I'd still have to
code the saving routines with respect to order of operation
(particularly if one component is 'aware' of another).
Ideally, I'd just like to have a load and save routine on the
CompositeObject. I would only need to add the IComponents I am
interested in at the time, before I call load or save and they would
be populated by the ORM layer.
Semantics aside, do you think this is something NHibernate could help
me achieve? If so, what do you think would be the most elegant way to
do it?
Best regards,
J.
--
You received this message because you are subscribed to the Google Groups
"nhusers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/nhusers?hl=en.