nhibernate/NHibernate.Mapping.Attributes

IdAttribute does not reflact it's Name attribute!

Closed this issue · 7 comments

For example, this is my City class with attribute mapping:

[Class(Schema = "public", Table = "cities")]
public class City {

    [Id(Column = "id", Type = "long", Generator = "trigger-identity")]
    public virtual long Id { get; set; }

    [Property(Column = "name", Type = "string", Length = 64, NotNull = true, Unique = true)]
    public virtual string Name { get; set; }

    [Property(Column = "population", Type = "int", NotNull = false)]
    public virtual int Population { get; set; }

}

the xml mapping generated is:

<class table="cities" schema="public" name="WebTest.Entities.City, WebTest">
  <id column="id" type="long" generator="trigger-identity" />
  <property name="Name" type="string" column="name" length="64" not-null="true" unique="true" />
  <property name="Population" type="int" column="population" not-null="false" />
</class>

the mapping for id is not corrent, will cause the Id property in result will be 0, because it is not mapped.

the work around is specify Name for IdAttribute :

[Id(Name = "Id", Column = "id", Type = "long", Generator = "trigger-identity")]
public virtual long Id { get; set; }

then the xml generated is correct:

<class table="cities" schema="public" name="WebTest.Entities.City, WebTest">
  <id name="Id" column="id" type="long" generator="trigger-identity" />
  <property name="Name" type="string" column="name" length="64" not-null="true" unique="true" />
  <property name="Population" type="int" column="population" not-null="false" />
</class>

Having at last taken time to look into this, it appears to me this is a by design limitation.
The id mapping element does not require a name. The identifier does not need to have a member in the entity. The property name is taken as a default only for attributes which requires a Name.

So you have to specify its name explicitly.

I am not sure this can be changed: this would be a breaking change for those relying on this behavior to declare the Id on some unrelated member, without any adverse effect due to not specifying a name and not needing having it hydrated in the entity. And also, how one would map an entity which does need to have its identifier among its members? Maybe it works by specifying the id on the class instead, but I have not seen any test for this.

Specify the IdAttribute on class is not allowed, please refer:

https://github.com/nhibernate/NHibernate.Mapping.Attributes/blob/master/src/NHibernate.Mapping.Attributes/IdAttribute.cs#L24

I am just curious about why PropertyAttribute can reflect the Property's name specified on, but IdAttribute can not.

And the CompositeIdAttribute is even more hard to use, no any docs about it, finally make it works like this:

[CompositeId]
[KeyProperty(Name = "MoniTime", Column = "moni_time", Type = "datetime" )]
[KeyProperty(Name = "StationId", Column = "station_id", Type = "long" )]
[KeyProperty(Name = "ItemId", Column = "item_id", Type = "long" )]
public virtual DateTime MoniTime { get; set; }

public virtual long StationId { get; set; }

public virtual long ItemId { get; set; }

[Property(Name = "Value", Column = "value", Type = "decimal", NotNull = false)]
public virtual decimal? Value { get; set; }

[Property(Name = "Description", Column = "description", Type = "string", NotNull = false, Length = 64)]
public virtual string Description { get; set; }

I am just curious about why PropertyAttribute can reflect the Property's name specified on, but IdAttribute can not.

It could, but this would harm the ability to have no name of this attribute, which mean an id without a property or field representing it into the entity. (Yes NHibernate supports this.) Since it can only be applied on members, if it was reflecting its name, there will be no way to map an Id without having it also hydrating an entity property.

OK, I know. But could you give some use cases about when to use this feature?

There are some test cases in NHibernate.Test doing that. Personally I have never used this feature and I have not searched about its usefulness. Still it is here, and so it is a legacy we have to maintain, unless there is a consensus for phasing it out.

thanks for your explanation, I think this issue can be closed now