I am looking for a way to gather appropriate MetaData from our database. We are using SQL Server so we have access to extended properties in both the table and columns.
What I am struggling with is how to decide when a table should be created as an EditableRoot, EditableChild, ReadOnlyRoot, etc.
Are there some guidelines for when these should be used like, if the current object is an EditableRoot then collections inside it should be EditableChildList? Or should I just fasten a property onto each table indicating which type of object to create and then also for each column to indicate what type of property to generate for that column?
This limits me to only creating properties of a single type unless I get really complex with the logic I use on my column level extended properties.
If I generate the Project table as both an EditableRoot and an EditableChild then what should I generate it's Department as? Department is a foreign key in the Project table so I can simply leave it as an int representing the ID of the Department or I can also emit a Department object as a member of the Project object. But should it be Editable or ReadOnly? Or the same as the parent object?
Thanks,
Will
One of the most difficult things to do here is to let go of the database schema for a few minutes and focus exclusively on object responsibility -> the way is it suppose to _look_ and _work_ from the users perspective and nothing else. You’ll be surprised at what will come out of this exercise. For example, if you come out of this and _feels_ that the Project BO should extend _some_ behavior for both Project and Department, then you code your Project BO as such – regardless of how they will be persisted in your database.
I think you're trying to create one BO for 1 database table - this is wrong :(.
Does this make any sense to you?
Hope this helps…
I am quite familiar with Dollard's ORM usage in code generation. I also understand the benefits of separating the business objects from the database schema. What we don't want though is the requirement of maintaing a really large ORM file that pretty much mimics the design of our database in a lot of respects.
That's why I am attempting to use the extended properties (I know these tie us to SQL Server but we're ok with that). I figure that using properties we can define what objects should be generated. We don't mind getting complex with these properties but we do want to keep them as simple as possible.
I don't want an object per table as I realize this yields poor business object design, however I am thinking of something like: At the table level I can have an extended property indicating what types of business objects to generate here (EditableRoot, EditableChild, etc).
On the column level I can just add extended properties for things like :"EmitAsEditableChildObject" or "EmitAsEditableRootObject", etc, when the column is a foreign key into another table and we want the parent object to have a child object and not just an ID.
This would save us from having to maintain a very large ORM file though we would still likely need one in some cases (an object that joins between tables).
Thoughts?
Another question we just happened upon with metadata gathering.
Using PTracher as an example, A Project has a ProjectResources collection in it. So, which kind of ProjectResources collection do we generate? EditableRootList, EditableChildList? ReadOnly?
I know this depends on use case, do we ever want to let the project object add and remove resources? Probably so. Now, what if we create a ReadOnlyRoot Project. What kind of ProjectResources collection should it have? Almost certainly of ReadOnlyList but of Root or Child?
One of my colleagues doesn't like the idea of being able to do things like
myProject.myProjectResources(0).Name = "BOB";
myProject.myProjectResources(0).Update()
He would prefer something like
EditableRootResource myRootResource = myProject.myProjectResources(0);
myRootResource.Name = "BOB;
myRootResource.Update();
Using his method, then the need of an EditableChildObject becomes completely useless and it's obviously a part of the architecture for a reason.
So, what are your opinions?
Thanks,
Will
Bayu:Just a though: you could equally well store the ORM details in relational structure and use a CSLA-based app to manage your ORM settings. Provides a nice test case as well: you have succeeded when your code-gen can generate your ORM maintenance tool.
That's another thing I have. I am supporting both web and windows applications and we obviously don't want separate libraries for each one.
As for creating all root objects, that sounds like it would complicate the library a lot. Even in web development you still have plenty of need for child objects and NameValue lists as well as the collection objects.
At least, I would think you'd still need child objects. I could be wrong. Maybe you are simply doing a schema of anytime you have an object with a collection of children you make it a collection off root objects and simply make it a child to the main object?
Will
This is what we have come up with so far. Let me know if you guys see any obvious, glaring, horrid flaws.
Thanks,
Will
//Generate an EditableRoot and ReadOnlyRoot for every object that has an ID field that is the sole PrimaryKey
if(ts.PrimaryKey.MemberColumns.Count == 1 && ts.PrimaryKey.MemberColumns.Contains("ID"))
{
WriteObject(xtw, ts, ds, "EditableRoot", ts.Name);
WriteObject(xtw, ts, ds, "ReadOnlyRoot", ts.Name);
}
//These are objects that require a parent object. They can not be instantiated alone in the system.
//If the table has a ParentObject and does NOT have a ChildObject
if(ts.ExtendedProperties.Contains("ParentObject") && !ts.ExtendedProperties.Contains("ChildObject"))
{
WriteObject(xtw, ts, ds, "EditableChild", ts.Name);
WriteObject(xtw, ts, ds, "ReadOnlyChild", ts.Name);
}
//Generate an EditableRootList and ReadOnlyRootList for every object that has an ID field that is the sole PrimaryKey,
//and has an extended property called Child
if(ts.ExtendedProperties.Contains("ChildObject"))
{
WriteObject(xtw, ts, ds, "EditableRootList", StringUtility.ToPlural(ts.Name));
WriteObject(xtw, ts, ds, "ReadOnlyRootList", StringUtility.ToPlural(ts.Name));
}
//Generate child lists when we have two columns as a primary key and neither column is called "ID"
//and when we need a list that is used as a collection inside of another object and not a standalone list.
if(ts.PrimaryKey.MemberColumns.Count == 2 && !ts.PrimaryKey.MemberColumns.Contains("ID") && ts.ExtendedProperties.Contains("ChildObject") && ts.ExtendedProperties.Contains("ParentObject"))
{
WriteObject(xtw, ts, ds, "EditableChildList", StringUtility.ToPlural(ts.Name));
WriteObject(xtw, ts, ds, "ReadOnlyChildList", StringUtility.ToPlural(ts.Name));
}
//Generate a NameValue list when we have an ID column and a NAME column and the ID column is the sole primary key.
if(ts.PrimaryKey.MemberColumns.Count == 1 && ts.PrimaryKey.MemberColumns.Contains("ID") && ts.Columns.Contains("Name"))
{
WriteObject(xtw, ts, ds, "NameValueList", ts.Name);
}
wjcomeaux:That's another thing I have. I am supporting both web and windows applications and we obviously don't want separate libraries for each one.
As for creating all root objects, that sounds like it would complicate the library a lot. Even in web development you still have plenty of need for child objects and NameValue lists as well as the collection objects.
At least, I would think you'd still need child objects. I could be wrong. Maybe you are simply doing a schema of anytime you have an object with a collection of children you make it a collection off root objects and simply make it a child to the main object?
Will
Using a couple of Interfaces and extending the base classes so that they implment those interfaces and have a variable called MyParent I can, for any object loaded, find the parent as well as the true root (which is responsible for initiating the save process.) But if you can't use session state there isn't much else you can do. You can still have Readonly roots and readonly children. I don't have any of them but they are still possible.Rocky talks about that hear.I guess it is hard but I have never done it any other way. What everybody else talks about hear seems much more difficult than what we do.
I'm using MyGeneration for my code gen and it comes with a very detailed MyMeta API to do exactly what you are suggesting.
I know its probably too late in the game for your to look into MyGenetation, but it might not be too late for others that will read this thread in the future :)
Do you know where one can find the CSLA templates for MyGeneration?
MyGeneration is written in .Net 1.1.
I created my own .Net project and referenced the MyMeta.dll, Zeus.dll, etc... from MyGeneration and then coded my own templates in c#. This way I was able to take full advantage of code complete and compile error when modifying my templates.
Here is a link... (They are 1.5 templates though, but it will give you an idea)
Nothing prevents you from using existing templates with the MyGeneration UI but I've always found that _free_ templates found on the web for any code generation tool will lack some functionality your personaly need. So I created my own templates for what I needed.
Clarification... The link provided above points to exiting templates on the web, they are not the one I wrote in c#.
Copyright (c) Marimer LLC