This project is read-only.

Polymorphic Associations limitations and questions

May 24, 2013 at 3:05 PM
From the doc
Each Link table has two columns that, in combination, specify the associated object: AssociatedRoleObjectType and AssociatedRoleObjectId. The latter is always an integer (one constraint of this pattern is that all objects that participate in the PA must have a single integer Id property called 'Id' in the code (the naming convention in the database is not mandated).
  1. Why is the Id limited to an integer? We run in a distributed environment with replication and hence we only use GUIDs for Ids. How can we achieve the same with GUIDs?
  2. For AssociatedRoleObjectType, is it correct that if we have a rename of an entity class, this would break the system unless we update the existing DB records to the new name?
  3. This is an explanation of the new way of doing PA. Where can I find documentation of the old way?
Thank you much.
May 24, 2013 at 3:30 PM
Why is the Id limited to an integer? We run in a distributed environment with replication and hence we only use GUIDs for Ids. How can we achieve the same with GUIDs?
This piece of work was originally done for a client that wanted integer Ids and did not want to use GUIDs. You could make exactly the same pattern work for GUIDs, making minor modifications to the helper classes. N.B. This approach to PAs is all done using helper classes that may be found in NakedObjects: it does not rely on any magic from the Naked Objects framework, so you are free to copy/re-write the helper classes to implement your own approach.
For AssociatedRoleObjectType, is it correct that if we have a rename of an entity class, this would break the system unless we update the existing DB records to the new name?
In essence, yes. Although you could use the TypeCodeMapper helper to use codes instead. Thus, if Customer was mapped as code CUS it wouldn't matter then if you renamed the class to, say, Client - if you didn't mind the database still having CUS.
This is an explanation of the new way of doing PA. Where can I find documentation of the old way?
Not sure that still exists anywhere. The helper classes do, in the form of:

IObjectFinder and the implementation ObjectFinder (these two were superseded by PolymorphicNavigator, which performs a similar role but with more sophistication).

If you look at the code of ObjectFinder you will see that it can cope with objects that have a GUID id - if they implement IHasGuid.

With not a huge effort you could understand how ObjectFinder detects the use of Guid and operates accordingly - and merge that same approach into the PolymorphicNavigator.

There was also a RoleIA code snippet, now gone, which I have dug out the definition for:
<?xml version="1.0" encoding="utf-8"?>
<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <SnippetTypes>
        <SnippetType>Expansion</SnippetType>
      </SnippetTypes>
      <Keywords />
      <Title>Role Interface Association</Title>
      <Author>Naked Objects Group</Author>
      <Description>Code to support an association defined by a 'role' Interface (one with mutiple implementations)</Description>
      <HelpUrl>www.nakedobjects.net</HelpUrl>
      <Shortcut>roleia</Shortcut>
    </Header>
    <Snippet>
      <References />
      <Imports />
      <Declarations>
        <Literal Editable="true">
          <ID>Name</ID>
          <ToolTip>The name for the property holding the associated object</ToolTip>
          <Default>PropertyName</Default>
          <Function>
          </Function>
        </Literal>
        <Object Editable="true">
          <ID>InterfaceType</ID>
          <ToolTip>The Interface defining the type of object to be associated</ToolTip>
          <Default>IType</Default>
          <Function>
          </Function>
          <Type>
          </Type>
        </Object>
      </Declarations>
      <Code Language="csharp" Kind="method decl" Delimiter="$"><![CDATA[
//Imports NakedObjects.Services  (you will need the no-helpers.dll assembly)

#region $Name$ Property of type $InterfaceType$ ('role' interface)

#region Injected: IObjectFinder
    //IMPORTANT:  Register an implementation of IObjectFinder e.g. ObjectFinder in Run class 
    //Suggestion: Move this property into an 'Injected Services' region

  public IObjectFinder ObjectFinder {protected get; set;}

#endregion

    //Holds a compound key that represents both the
    //actual type and the identity of the associated object.
    [Hidden()]
    public virtual string $Name$CompoundKey {get; set;}

    private $InterfaceType$ _$Name$;

    [NotPersisted()]
    public $InterfaceType$ $Name$ {
        get {
            if (_$Name$ == null & (! (string.IsNullOrEmpty($Name$CompoundKey)))) {
                _$Name$ = ObjectFinder.FindObject<$InterfaceType$>($Name$CompoundKey);
            }
            return _$Name$;
        }
        set {
            _$Name$ = value;
            if (value == null) {
                $Name$CompoundKey = null;
            }
            else {
                $Name$CompoundKey = ObjectFinder.GetCompoundKey<$InterfaceType$>(value);
            }
        }
  }
  #endregion]]></Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>
Jun 5, 2013 at 10:47 AM
This is optionally added by the 'second half' table(s), which are added by DBAs or developers, when the domain model design has stabilised. The database diagram below shows the schema after the addition of these second half tables:
If these tables are not mapped in the entity model, how will they get correctly populated?
Jun 5, 2013 at 11:08 AM
I need to add a further comment into the doc ...

If you want to use the second half table, then these need to be created and maintained by database triggers.
Jun 5, 2013 at 11:18 AM
I suspected as much. :)
Tnx
Jun 5, 2013 at 11:25 AM
You mean that PayeeLinks should have a trigger on it to populate either PayeeLinks_Customers or PayeeLinks_Employers?
So then the trigger needs to contain conditional logic about the entity type?
Jun 5, 2013 at 11:37 AM
You mean that PayeeLinks should have a trigger on it to populate either PayeeLinks_Customers or PayeeLinks_Employers?
So then the trigger needs to contain conditional logic about the entity type?
Yes. Like Churchill said about democracy - it's a really bad idea until you consider the alternatives. Remember that the second half tables are optional - you only add them if database referential integrity is considered mandatory. (Increasingly, systems are being built with no RI at the database level at all.)
Jun 5, 2013 at 12:07 PM
Like Churchill said about democracy
I don't like it when you keep mentioning that. :P