missing: support for navigation-properties on components

Discussion of open issues, suggestions and bugs regarding Entity Developer - ORM modeling and code generation tool
mindplay
Posts: 148
Joined: Tue 13 Dec 2011 22:58
Location: Ithaca, NY

missing: support for navigation-properties on components

Post by mindplay » Thu 05 Jan 2012 20:19

Somewhat shockingly, I just realized that all navigation-properties from my existing imported NHibernate mapping files were discarded on import!

And then furthermore, I discovered that relations between entities and components don't seem to be supported by ED at all?

I have one entity with around 240 properties in about 10 different components, and this is all pre-existing code and tables, so there really is no way around this - I have to map these as components.

Having this many properties on one entity is not generally my cup of tea, but my client really needs to record over 200 different properties on this one entity - and all of them need to be queryable, and the queries need to run fast, so there was no good way to avoid this...

I'm almost 100 hours into porting a huge data-model to ED, we've purchased the software, and I'm almost done. I should have realized early on that this feature was unsupported, but you do advertise support for "all kinds of mappings", which I took as meaning all kinds of mappings supported by NH.

It never occurred to me that these properties were missing - the HBM importer did not notify me that anything was being discarded during import.

Any chance this feature will be added in the near future?

Helen
Devart Team
Posts: 127
Joined: Wed 07 Sep 2011 11:54

Post by Helen » Tue 10 Jan 2012 10:29

Thank you for your suggestions.

We will investigate the possibility of implementing this feature in Entity Developer. We will notify you about the results as soon as possible.

Helen
Devart Team
Posts: 127
Joined: Wed 07 Sep 2011 11:54

Post by Helen » Fri 13 Jan 2012 10:06

Our investigation is in progress and we need more information:
1) Please specify which kind of mapping you need in more details. As we understood, you need support for Collections of dependent objects, which are described in the 7.2 paragraph of NHibernate Reference Documentation ?
2) Please describe your model in more details: if there are connected entities in the model, etc. If possible, please send us your model or the part of it that contains objects and a sample of the required mapping.

mindplay
Posts: 148
Joined: Tue 13 Dec 2011 22:58
Location: Ithaca, NY

Post by mindplay » Fri 13 Jan 2012 18:33

Yes, exactly that - what you referenced in paragraph 7.2 of the documentation:

Code: Select all

<class name="Order" .... >
    ....
    <set name="PurchasedItems" table="purchase_items" lazy="true">
        <key column="order_id">
        <composite-element class="Purchase">
            <property name="PurchaseDate"/>
            <property name="Price"/>
            <property name="Quantity"/>
            <many-to-one name="Item" class="Item"/> <!-- class attribute is optional -->
        </composite-element>
    </set>
</class>   
The many-to-one on the Purchase composite currently cannot be modeled - and the same of course for many-to-many mappings on a composite.

In my existing application, a number of components have properties with varying collection types. I don't think you would gain anything from seeing my code - it's similar to the example you mentioned.

Navigation properties on components, as far as I understand, have all of the same capabilities as navigation-properties on any other entity - from NHibernate's perspective, they are pretty much treated the same. The mappings of course are nested differently, but are otherwise the same, as far as I understand...

Helen
Devart Team
Posts: 127
Joined: Wed 07 Sep 2011 11:54

Post by Helen » Mon 16 Jan 2012 10:37

Thank you for a detailed description of your vision of this issue. We are studying the possibility of implementing this feature.

We will inform you about the results as soon as possible.

Helen
Devart Team
Posts: 127
Joined: Wed 07 Sep 2011 11:54

Post by Helen » Mon 23 Jan 2012 15:05

The support for collections of dependent objects is added.

This functionality will be available in the nearest public build.

Helen
Devart Team
Posts: 127
Joined: Wed 07 Sep 2011 11:54

Post by Helen » Fri 27 Jan 2012 12:52

The feature is available in the latest 4.2.120 build of Entity Developer.
The new build can be downloaded from http://www.devart.com/entitydeveloper/download.html (the trial and free versions) or from Registered Users' Area (provided that you have an active subscription).

For more information, please refer to http://www.devart.com/forums/viewtopic.php?t=23252 .

mindplay
Posts: 148
Joined: Tue 13 Dec 2011 22:58
Location: Ithaca, NY

Post by mindplay » Mon 30 Jan 2012 20:41

Just installed 4.2.120 (27-Jan-2012) and I don't see this feature?

Checked my about box and it says 4.2.120 after install.

My guess was you would right-click a component and select "Add Assocation", same as for classes - but all I see is "Add Property", and nothing new in the property dialog.

How do I access this feature?

Helen
Devart Team
Posts: 127
Joined: Wed 07 Sep 2011 11:54

Post by Helen » Tue 31 Jan 2012 11:29

The "Add Association" command in the shortcut menu is unavailable for complex types because in fact a class contains a collection of complex types. And a complex type conceptually is not related with a class or an association.

Thats why you need to right-click the corresponding class an select "Add Association" from the shortcut menu, then select the corresponding complex type in the "Class" combobox for the End2 , and then set other association parameters.

mindplay
Posts: 148
Joined: Tue 13 Dec 2011 22:58
Location: Ithaca, NY

Post by mindplay » Tue 31 Jan 2012 19:51

That seems odd, why wouldn't I be able to create this relationship from either one end or the other, same as any other relationship?

Complex types may not be conceptually related with classes in your software - but in design terms, and in terms of NH support for these patterns, an entity (class) and a complex type (component) really aren't any different at all - they're just located in different places in the object model graph. They're both just objects of a given type.

To prove my point - NH actually permits you to map the same type in both ways. So for example, Address might be mapped as an entity to a table in one situation, and used as a component (mapped to columns on another entity) in another situation.

Having a strict separation between so-called complex types and classes really isn't very meaningful, in my opinion. For instance, a competing product, NHibernate Designer doesn't make this distinction - types are just types, whereas there are multiple types of associations, which determine how the mappings are actually implemented. This is how models are generally documented using standard UML class diagrams/tools as well - the arrows define the kind of relationship one type has with another; there's only kind of "type".

I realize that's just a different way to look at things, and you chose a different approach - all I'm saying is, this model more accurately resembles the traditional relational model, as implemented by various standards, such as UML class diagrams.

Anyway, some more practical notes...

I didn't notice that complex types are now listed on the drop-down, because the drop-down is not longer alphabetized.

Also, selecting a complex type from the dropdown pops up an error message saying "Cannot uncheck both Generate properties", although "Generate related property" is checked for End 1.

Navigation properties also aren't displayed on complex types.

It looks like you normalized some of the common features between classes and complex types by adding an interface? It still looks to me as if classes and complex types have more in common - in fact, they should be largely the same, and the workflow definitely would be more streamlined if they behaved the same way in the user-interface.

The terminology itself is kind of "off" - you have something called a "class", and another thing called a "complex type", but complex types really are just classes with a different purpose. But they're still classes. I'm not sure treating them as something fundamentally different is really the right way to go...

mindplay
Posts: 148
Joined: Tue 13 Dec 2011 22:58
Location: Ithaca, NY

Post by mindplay » Tue 31 Jan 2012 20:33

I don't understand how this works.

I can only add the Association from the opposite side of the complex type, so I click on the other class, and select "Add Association".

Only "End 2" offers complex types in the Class drop-down, so I select the complex type from there.

At this point, I see a "Join Table" input, and all the properties of the complex type listed under "Composite element mapping" below, implying that a whole table is going to be generated to store instance of the complex type??

I don't understand what would be the point of this at all - you can already model the exact same thing by adding a normal class (rather than a complex type) and a relationship with another class.

I'm afraid what you've done is the exact opposite of what I was asking for?

It seems you have the ability to add many instance of a complex type as a collection on another class.

What I was looking for, was the ability to add navigation properties to complex types. I believe that's what the example you posted demonstrates:

Code: Select all

         
        <composite-element class="Purchase">
            <property name="PurchaseDate"/>
            <property name="Price"/>
            <property name="Quantity"/>
            <many-to-one name="Item" class="Item"/> <!-- here! -->
        </composite-element>              
What I'm looking for here, is the many-to-one - outgoing navigation from a property on a component, not the other way around.

Mapping "complex types" the way your new feature permits, comes back to my argument (above) that complex types really are just classes. Giving them special status means they need special treatment, but this type of mapping really was already possible, using a "class" rather than a "complex type"...

But maybe I have completely misunderstood how this works?

I looked in the documentation, but I don't see anything documenting how to configure navigation properties on complex types. Could you point out the right place to look, or maybe post an example or further explanation?

mindplay
Posts: 148
Joined: Tue 13 Dec 2011 22:58
Location: Ithaca, NY

Post by mindplay » Tue 31 Jan 2012 22:00

Sorry for mass posting here.

I created an example to illustrate the need and the problem, plus another problem I ran into while creating this example.

Here's a sample project:

https://docs.google.com/open?id=0BxKmkm ... k0ZmVhZjE2

First off, try to generate the schema - it won't work. Clearly there is some kind of checking here that doesn't work like it's supposed to - the BillingAddress and ShippingAddress properties have different prefixes, so they don't really overlap, but the error message says they do.

This is the second problem, which is unrelated to the problem I'm trying to demonstrate. To work around the second problem, for now just delete the ShippingAddress property.

The following schema is generated:

Code: Select all

CREATE TABLE dbo.Countries (
   Id INT NOT NULL IDENTITY,
   Name VARCHAR(MAX) NOT NULL,
   CONSTRAINT PK_Countries PRIMARY KEY (Id)
)
GO

CREATE TABLE dbo.Customers (
   Id INT NOT NULL IDENTITY,
   Name VARCHAR(MAX) NOT NULL,
   Billing_Street VARCHAR(MAX) NOT NULL,
   Billing_City VARCHAR(MAX) NOT NULL,
   CONSTRAINT PK_Customers PRIMARY KEY (Id)
)
GO
The first problem is this: the Address component needs a Country navigation property, associated with the Country type on the diagram.

So in terms of schema, I would expect to see a Billing_CountryId column on the table Customers.

I don't think what you implemented allows me to do that?

Helen
Devart Team
Posts: 127
Joined: Wed 07 Sep 2011 11:54

Post by Helen » Wed 01 Feb 2012 16:08

mindplay wrote: I didn't notice that complex types are now listed on the drop-down, because the drop-down is not longer alphabetized.
We will change the sort order in the "Class" drop-down for the "End 2" in the Association Editor.
mindplay wrote: Also, selecting a complex type from the dropdown pops up an error message saying "Cannot uncheck both Generate properties", although "Generate related property" is checked for End 1.
Thank you for the report, we have reproduced the problem.
We will fix it and inform you when the corresponding build is available.
mindplay wrote: First off, try to generate the schema - it won't work. Clearly there is some kind of checking here that doesn't work like it's supposed to - the BillingAddress and ShippingAddress properties have different prefixes, so they don't really overlap, but the error message says they do.
We have fixed the bug with script generation when there is an entity in the model that has several complex type properties of the same complex type.
mindplay wrote: Navigation properties also aren't displayed on complex types.
A component is a contained object that is persisted as a value type, not an entity.
Components cannot have navigation properties, that's why there no navigation properties in complex types on a diagram. Only an entity can contain a collection of components.
If you don't want to use all the table columns, but only part of the table, you may create a complex type (component) with the properties you want to retrieve from the table, and create an association to this complex type and specify the table name and foreign key columns in the association settings . It does not differ much from creating association between two entities. The difference is that table is partially mapped to the component, instead of being mapped entirely to the entity. This component does not have and cannot have the reference to the entity, - the entity will have a collection of the components.

"Composite elements may contain components but not collections" ( see http://www.nhforge.org/doc/nh/en/index. ... ollections). Besides, the same section says: "A special case of a composite element is a composite element with a nested element. A mapping like this allows you to map extra columns of a many-to-many association table to the composite element class".
I.e. when creating a many-to-many association, if the join table (the one that connects two tables that corresponds to the ends of the association) contains additional columns (not just foreign key columns), you may use component to retrieve them. In this case a complex type, having the properties we want to retrieve, is created and specified in the Component box of the Association Editor for the many-to-many association. In the generated code, the classes, corresponding to the entities on the ends of this many-to-many association, will have the collections of complex types, containing the properties, corresponding to the additional columns of the join table, and the reference to the opposite entity class. NHibernate does not have other ways to use the collections of dependent objects. It's impossible to create the mapping you've described, NHibernate does not allow it.
If you want, we can send you Entity Developer models, which demonstrate the features, related to the collections of dependent objects, that are supported in NHibernate.

mindplay
Posts: 148
Joined: Tue 13 Dec 2011 22:58
Location: Ithaca, NY

Post by mindplay » Wed 01 Feb 2012 17:35

Components cannot have navigation properties, that's why there no navigation properties in complex types on a diagram. Only an entity can contain a collection of components.
Yes, but that's not what I'm asking for - I realize you can't have collections of objects attached to a component, but that's not what I'm trying to do.

Here's an excerpt of the mappings in my existing project - this is a functioning mapping:

Code: Select all

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class xmlns="urn:nhibernate-mapping-2.2" name="MyApp.Entities.Location" table="Location">
    <id name="Id" type="System.Int32" unsaved-value="0">
      <column name="Id" />
      <generator class="identity" />
    </id>
    <property name="Name" type="System.String">
      <column name="Name" length="120" not-null="true" />
    </property>
    <component name="CustomerFinance" insert="true" update="true" optimistic-lock="true" class="MyApp.Entities.LocationFinance">
      <property name="TaxPayerId" type="System.String">
        <column name="CustomerFinance_TaxPayerId" length="50" />
      </property>
      <many-to-one cascade="none" class="MyApp.Entities.Country" name="Country">
        <column name="CustomerFinance_CountryId" />
      </many-to-one>
    </component>
    <component name="VendorFinance" insert="true" update="true" optimistic-lock="true" class="MyApp.Entities.LocationFinance">
      <property name="TaxPayerId" type="System.String">
        <column name="VendorFinance_TaxPayerId" length="50" />
      </property>
      <many-to-one cascade="none" class="MyApp.Entities.Country" name="Country">
        <column name="VendorFinance_CountryId" />
      </many-to-one>
    </component>
  </class> 
As you can see, I have two different LocationFinance instances as components on my Location entity, and each of those reference a Country.

This is similar to the example I posted above, and the example you posted ealier from the documentation.

It's equivalent to the second example in the documentation reference you just posted - the "special case" mentioned is what I'm looking for.

Currently, I would have to put these country references as properties on the Location type, but then what's the point of using components to begin with? This doesn't give me any uniform way to program against these component instances, because the information they will carry with them is going to be incomplete, which would complicate everything from business logic down to controllers through to view-models.

If ED isn't going to support this mapping-feature, I will have to write and maintain these mappings by hand - this particular table, classes and mappings consists of over 240 properties, so you can see why I'm trying to avoid this...

Helen
Devart Team
Posts: 127
Joined: Wed 07 Sep 2011 11:54

Post by Helen » Fri 03 Feb 2012 12:47

mindplay wrote:It's equivalent to the second example in the documentation reference you just posted - the "special case" mentioned is what I'm looking for.
The "special case" describes working with component's navigation properties in case of many-to-many association, but not with component property includes navigation property to another entity.
mindplay wrote:Here's an excerpt of the mappings in my existing project - this is a functioning mapping..
Your code sample considerably differs from the one we have discussed before:
Helen wrote:1) Please specify which kind of mapping you need in more details. As we understood, you need support for Collections of dependent objects, which are described in the 7.2 paragraph of NHibernate Reference Documentation
mindplay wrote:Yes, exactly that - what you referenced in paragraph 7.2 of the documentation.
We will investigate the possibility of implementing this mapping-feature (which are described in the 5.1.13 paragraph of NHibernate Reference Documentation) in Entity Developer.

Post Reply