Implementing default item hierarchy declarativelly

Topics: Developer Forum
Aug 29, 2008 at 11:16 AM
A brainstorming question for N2 gurus:
How would you implement the following snippet:

[EnsureChildren(typeof(InboxItem), typeof(DraftsItem), typeof(SentItem))]
public class MailBox: ContentItem

What I'd like to get as a result of instantiating the above class, is an example MailBox item with a single (let's assume a simplest case of cardinality 1 for now) child of each type, specified in a hypothetical EnsureChildrenAttribute. Moreover, it would be nice to have this integrity check work for existing items upon their retrieval.

How would you implement the processing of such EnsureChildrenAttribute?

I see 2 ways of implementing the logic:
  1. Encapsulate attribute processing in a ContentItem descendant and derive from it afterwards. Pro: easy to track a moments where it makes sense to check for the presense of children. Cons: Introduce a dependency on infrastructure directly inside an entity class.
  2. Introduce a dedicated plugin, which would subscribe to persistance events. Pro: minimal intrusion into entity class. Cons: performance hit by another plugin inspecting every persistance action in the system.
  3. Your ideas? ... ;-)
Aug 30, 2008 at 12:15 AM
The easist way in the current state of the code is probably like you say. Perhaps adding them during N2.Context.Definitions.ItemCreated and control their continued existance with the persistence events.

Another solution is creating them when the item is edited as in the start page code.

I can see the value of defining certain items as integral parts of container whose existence can be depended upon.

I think it would be useful to lock each item to a certain name:

[EnsureChild("Inbox", typeof(InboxItem))]
[EnsureChild("Drafts", typeof(DraftsItem))]
[EnsureChild("Sent", typeof(SentItem))]
public class MailBox: ContentItem

The framework could treat the attributes as processors and ask them what to do in certains situations such as movements and deletions.
Sep 1, 2008 at 3:43 PM
<iframe marginheight="0" marginwidth="0" style="border: 1px solid rgb(221, 229, 233); margin: 3px; padding: 0pt; width: 240px; height: 26px; background-color: rgb(255, 255, 255);" src="" scrolling="no" frameborder="0"></iframe>

Somehow, i've managed to assemble a workable solution as you've outlined it:
- with a single attribute instance for each child definition
- another controller class for applying attribute action
- and, finally, an initializer for controller class through dependency injection

Though, i expect still much work has to be done.

Though, conceptually, the better description of the purpose of this exercise is as you've put it: "defining certain items as integral parts of container"
Sep 1, 2008 at 8:01 PM
Good stuff. I like it.

Would you like to finalize this in the trunk if I grant some write access? Preferably with some unit tests. Let me know, you'll have to send me a google account email.
Sep 2, 2008 at 7:06 PM
<iframe marginheight="0" marginwidth="0" style="border: 1px solid rgb(221, 229, 233); margin: 3px; padding: 0pt; width: 240px; height: 26px; background-color: rgb(255, 255, 255);" src="" scrolling="no" frameborder="0"></iframe>

Here is my turn: EnsureChildrenAttribute and dependencies packaged into separate project, plus some sketches for tests. I could not find out how to make the latter work -- i guess there should be some special way to start n2 runtime during nunit execution -- 'll proceed with it tomorrow. Also, 'd like to heare some opinion regarding tests design -- there is much to be learned for me in this area.

Here's my reasoning why it makes sense to move surrounding logic into separate assembly: in general, i supose, the developer must have a control over what plugins are loaded. If they are packaged into main N2.dll assembly and decorated with [AutoInitialize] they'll be loaded no matter what, right ? So the only way to control plugins instantiation seems to move them elsewhere, allowing to reference them as needed.

Sep 3, 2008 at 6:52 PM
Looks promising. Intention relvealing test names. I copied app.config from the n2.tests project referenced and ran the tests.

I noticed that ItemBuilder saves the child entities before the parent item has been saved which causes an exception. You shouldn't need to save them, nhibernate should take care of persisting the item tree.

I see your point about having a library. It's your call. Perhaps we can reconsider once the functionality is stabilized.
Sep 10, 2008 at 3:07 PM
Regarding persisting item tree: is it correct to say that it sufficient to call Definition.CreateInstance(ChildType, parent) to have child automagically created after Persister.Save(parent) without calling Save(child) ? I seem not to get this result in my case: child item does neither exist after CreateInstance(..), nor after Save(parent). Integrity check seems to pass just fine.
Sep 10, 2008 at 3:18 PM
Aha ! (an Eureka moment!) The child.AddTo(parent) is needed as well.
Sep 10, 2008 at 4:57 PM
Sorry, yet another question regarding items interdependencies:

Doesn't it make sense to extend RestrictParentAttribute and AllowedChildrenAttribute applicability to AttributeTargets.Interface ? Ain't it gonna break anything ?