From dc8ad491b665d3cdf6834e572569c5c7b0817696 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Delaporte?= <12201973+fredericdelaporte@users.noreply.github.com> Date: Fri, 25 May 2018 11:15:02 +0200 Subject: [PATCH] Update mapping documentation Many mapping properties available in NHibernate are lacking proper documentation. Document them. (Mainly done by synchronizing with https://docs.jboss.org/hibernate/orm/3.5/reference/en-US/html/mapping.html and subsequent chapters of the Hibernate documentation.) Also fixes inaccuracies and misleading statements. --- doc/reference/master.xml | 2 + doc/reference/modules/associations.xml | 628 +++++ doc/reference/modules/basic_mapping.xml | 2302 ++++++++++++----- doc/reference/modules/collection_mapping.xml | 1798 ++++++++----- doc/reference/modules/component_mapping.xml | 227 +- doc/reference/modules/example_mappings.xml | 320 ++- doc/reference/modules/example_parentchild.xml | 422 +-- doc/reference/modules/filters.xml | 12 +- doc/reference/modules/inheritance_mapping.xml | 346 ++- doc/reference/modules/manipulating_data.xml | 15 +- doc/reference/modules/performance.xml | 2 +- doc/reference/modules/persistent_classes.xml | 2 +- src/NHibernate/Async/Id/CounterGenerator.cs | 2 +- .../Async/Id/IdentifierGeneratorFactory.cs | 4 +- .../Async/Id/SequenceIdentityGenerator.cs | 2 +- src/NHibernate/Async/Id/TableGenerator.cs | 2 +- src/NHibernate/Id/CounterGenerator.cs | 9 +- .../Id/IdentifierGeneratorFactory.cs | 26 +- src/NHibernate/Id/IncrementGenerator.cs | 2 +- .../Id/SequenceIdentityGenerator.cs | 4 +- src/NHibernate/Id/TableGenerator.cs | 2 +- src/NHibernate/Id/TableHiLoGenerator.cs | 6 +- src/NHibernate/Id/TriggerIdentityGenerator.cs | 6 +- 23 files changed, 4205 insertions(+), 1936 deletions(-) create mode 100644 doc/reference/modules/associations.xml diff --git a/doc/reference/master.xml b/doc/reference/master.xml index 66150037aa5..0911ee476e1 100644 --- a/doc/reference/master.xml +++ b/doc/reference/master.xml @@ -8,6 +8,7 @@ + @@ -55,6 +56,7 @@ &basic-mapping; &collection-mapping; + &associations; &component-mapping; &inheritance-mapping; diff --git a/doc/reference/modules/associations.xml b/doc/reference/modules/associations.xml new file mode 100644 index 00000000000..c5ea1f62725 --- /dev/null +++ b/doc/reference/modules/associations.xml @@ -0,0 +1,628 @@ + + Association Mappings + + + Introduction + + + Association mappings are often the most difficult thing to implement correctly. In this section + we examine some canonical cases one by one, starting with unidirectional mappings and then + bidirectional cases. We will use Person and Address in all + the examples. + + + + Associations will be classified by multiplicity and whether or not they map to an intervening join table. + + + + Nullable foreign keys are not considered to be good practice in traditional data modelling, so our + examples do not use nullable foreign keys. This is not a requirement of NHibernate, and the mappings + will work if you drop the nullability constraints. + + + + + + Unidirectional associations + + + Many-to-one + + + An unidirectional many-to-one association is the most common kind of + unidirectional association. + + + + + + + + + + + + + +]]> + + + + + + + One-to-one + + + An unidirectional one-to-one association on a foreign key is almost + identical to a many-to-one. The only difference is the column unique constraint. + + + + + + + + + + + + + +]]> + + + + + An unidirectional one-to-one association on a primary key usually uses + a special id generator In this example, however, we have reversed the direction of the + association: + + + + + + + + + + + + Person + + + +]]> + + + + + + + One-to-many + + + An unidirectional one-to-many association on a foreign key is an + unusual case, and is not recommended. + + + + + + + + + + + + + + + + +]]> + + + + + + + + + Unidirectional associations with join tables + + + One-to-Many + + + An unidirectional one-to-many association on a join table is the + preferred option. Specifying unique="true" changes the multiplicity + from many-to-many to one-to-many. + + + + + + + + + + + + + + + + +]]> + + + + + + + Many-to-one + + + An unidirectional many-to-one association on a join table is common + when the association is optional (while avoiding nullable foreign key). + + + + + + + + + + + + + + + + +]]> + + + + + + + One-to-one + + + An unidirectional one-to-one association on a join table is possible, + but extremely unusual. + + + + + + + + + + + + + + + + +]]> + + + + + + + Many-to-many + + + Finally, here is an example of an unidirectional many-to-many association. + + + + + + + + + + + + + + + + +]]> + + + + + + + + + Bidirectional associations + + + One-to-many / many-to-one + + + A bidirectional many-to-one association is the most common kind of + association. The following example illustrates the standard parent/child relationship. + + + + + + + + + + + + + + + + + +]]> + + + + + If you use an IList, or other indexed collection, set the + key column of the foreign key to not null. NHibernate + will manage the association from the collections side to maintain the index of each element, + making the other side virtually inverse by setting update="false" and + insert="false": + + + + + + + + + + + + + + + + + + +]]> + + + + + When the underlying foreign key column is NOT NULL, it is important + that you define not-null="true" on the <key> + element of the collection mapping. Do not only declare not-null="true" + on a possible nested <column> element, but always declare it on + the <key> element too. + + + + + + One-to-one + + + A bidirectional one-to-one association on a foreign key is common. + + + + + + + + + + + + + + +]]> + + + + + A bidirectional one-to-one association on a primary key uses the + special foreign id generator. + + + + + + + + + + + + + Person + + + +]]> + + + + + + + + + Bidirectional associations with join tables + + + One-to-many / many-to-one + + + The following is an example of a bidirectional one-to-many association on a + join table. The inverse="true" can go on either end of + the association, on the collection, or on the join. + + + + + + + + + + + + + + + + + + + + +]]> + + + + + + + One-to-one + + + A bidirectional one-to-one association on a join table is possible, + but extremely unusual. + + + + + + + + + + + + + + + + + + + + +]]> + + + + + + + Many-to-many + + + Here is an example of a bidirectional many-to-many association. + + + + + + + + + + + + + + + + + + + + +]]> + + + + + + + + + More complex association mappings + + + More complex association joins are extremely rare. NHibernate handles + more complex situations by using SQL fragments embedded in the mapping document. For example, + if a table with historical account information data defines AccountNumber, + EffectiveEndDate and EffectiveStartDatecolumns, it would + be mapped as follows: + + + + + + case when EffectiveEndDate is null then 1 else 0 end + + + +]]> + + + You can then map an association to the current instance, the one with null + EffectiveEndDate, by using: + + + + + '1' +]]> + + + In a more complex example, imagine that the association between Employee and + Organization is maintained in an Employment table full of + historical employment data. An association to the employee's most recent + employer, the one with the most recent startDate, could be mapped in the + following way: + + + + + + select employeeId, orgId + from Employments + group by orgId + having startDate = max(startDate) + + +]]> + + + This functionality allows a degree of creativity and flexibility, but it is more practical to + handle these kinds of cases by using queries. + + + + + diff --git a/doc/reference/modules/basic_mapping.xml b/doc/reference/modules/basic_mapping.xml index 1cc8e06fac1..747389b53ae 100644 --- a/doc/reference/modules/basic_mapping.xml +++ b/doc/reference/modules/basic_mapping.xml @@ -28,37 +28,37 @@ - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + ]]> - We will now discuss the content of the mapping document. We will only describe the + We will now discuss the content of the mapping document. We will mainly describe the document elements and attributes that are used by NHibernate at runtime. The mapping document also contains some extra optional attributes and elements that affect the - database schemas exported by the schema export tool. (For example the - not-null attribute.) + database schemas exported by the schema export tool. (By example the + column sub-element of a property.) @@ -86,9 +86,9 @@ hibernate-mapping - This element has several optional attributes. The schema attribute - specifies that tables referred to by this mapping belong to the named schema. If specified, - table names will be qualified by the given schema name. If missing, table names will be + This element has several optional attributes. The schema and catalog attributes + specify that tables referred to by this mapping belong to the named schema and/or catalog. If they are specified, + table names will be qualified by the given schema and/or catalog name. If they are missing, table names will be unqualified. The default-cascade attribute specifies what cascade style should be assumed for properties and collections which do not specify a cascade attribute. The auto-import attribute lets us @@ -97,77 +97,91 @@ are located and the namespace they are declared in. - - - - - - - - - - - + + + + + + + + + + + ]]> - - - - schema (optional): The name of a database schema. - - - - - default-cascade (optional - defaults to none): - A default cascade style. - - - - - auto-import (optional - defaults to true): - Specifies whether we can use unqualified class names (of classes in this mapping) - in the query language. - - - - - assembly and namespace(optional): Specify - assembly and namespace to assume for unqualified class names in the mapping - document. - - - - - default-access (optional - defaults to property): - The strategy NHibernate should use for accessing a property value - - - - - default-lazy (optional - defaults to true): - Lazy fetching may be completely disabled by setting default-lazy="false". - - - - - - - If you are not using assembly and namespace - attributes, you have to specify fully-qualified class names, including the name - of the assembly that classes are declared in. - - - - If you have two persistent classes with the same (unqualified) name, you should set - auto-import="false". NHibernate will throw an exception if you attempt - to assign two classes to the same "imported" name. - + + + + schema (optional): The name of a database schema. + + + + + catalog (optional): The name of a database catalog. + + + + + default-cascade (optional - defaults to none): + A default cascade style. + + + + + auto-import (optional - defaults to true): + Specifies whether we can use unqualified class names of classes in this mapping + in the query language. + + + + + assembly and namespace (optional): Specify + assembly and namespace to use for unqualified class names in the mapping document. + + + + + default-access (optional - defaults to property): + The strategy NHibernate should use for accessing a property value. It can be a custom + implementation of IPropertyAccessor. + + + + + default-lazy (optional - defaults to true): + The default value for unspecified lazy attributes of class and collection mappings. + + + + + + + If you are not using assembly and namespace + attributes, you have to specify fully-qualified class names, including the name + of the assembly that classes are declared in. + + + + If you have two persistent classes with the same (unqualified) name, you should set + auto-import="false". NHibernate will throw an exception if you attempt + to assign two classes to the same "imported" name. + + + + The hibernate-mapping element allows you to nest several persistent <class> + mappings, as shown above. It is, however, good practice to map only a single persistent class, or a single class + hierarchy, in one mapping file and name it after the persistent super-class. For example, Cat.hbm.xml, + Dog.hbm.xml, or if using inheritance, Animal.hbm.xml. + @@ -195,24 +209,38 @@ + + + + + + + ]]> @@ -228,46 +256,52 @@ - discriminator-value (optional - defaults to the class name): A value + discriminator-value (optional, defaults to the class name): A value that distinguishes individual subclasses, used for polymorphic behaviour. Acceptable values include null and not null. - mutable (optional, defaults to true): Specifies + mutable (optional - defaults to true): Specifies that instances of the class are (not) mutable. - schema (optional): Override the schema name specified by + schema (optional): Overrides the schema name specified by the root <hibernate-mapping> element. - proxy (optional): Specifies an interface to use for lazy - initializing proxies. You may specify the name of the class itself. + catalog (optional): Overrides the catalog name specified by + the root <hibernate-mapping> element. - dynamic-update (optional, defaults to false): - Specifies that UPDATE SQL should be generated at runtime and - contain only those columns whose values have changed. + proxy (optional): Specifies an interface to use for lazy + initializing proxies. You may specify the name of the class itself. - dynamic-insert (optional, defaults to false): - Specifies that INSERT SQL should be generated at runtime and - contain only the columns whose values are not null. + dynamic-update (optional - defaults to false): + Specifies that UPDATE SQL should be generated at runtime and + can contain only those columns whose values have changed. - select-before-update (optional, defaults to false): + dynamic-insert (optional - defaults to false): + Specifies that INSERT SQL should be generated at runtime and + contain only the columns whose values are not null. + + + + + select-before-update (optional - defaults to false): Specifies that NHibernate should never perform an SQL UPDATE unless it is certain that an object is actually modified. In certain cases (actually, only when a transient object has been associated with a new session using update()), @@ -275,45 +309,83 @@ if an UPDATE is actually required. - + - polymorphism (optional, defaults to implicit): + polymorphism (optional - defaults to implicit): Determines whether implicit or explicit query polymorphism is used. - + where (optional) specify an arbitrary SQL WHERE - condition to be used when retrieving objects of this class + condition to be used when retrieving objects of this class. - + persister (optional): Specifies a custom IClassPersister. - + - batch-size (optional, defaults to 1) specify a "batch size" - for fetching instances of this class by identifier. + batch-size (optional - defaults to 1): Specifies a "batch size" + for fetching instances of this class by identifier. See . - + - optimistic-lock (optional, defaults to version): + optimistic-lock (optional - defaults to version): Determines the optimistic locking strategy. - - + + - lazy (optional): Lazy fetching may be completely disabled by setting - lazy="false". + lazy (optional - defaults to true): Lazy fetching can be + disabled by setting lazy="false". - + + + abstract (optional - defaults to false): Used to mark abstract + super-classes in <union-subclass> hierarchies. + + + + + entity-name (optional - defaults to the class name): NHibernate allows a class to + be mapped multiple times, potentially to different tables. See . + It also allows entity mappings that are represented by dictionaries at the .Net level. In these cases, + you should provide an explicit arbitrary name for the entity. See + for more information. + + + + + check (optional): An SQL expression used to generate a multi-row check constraint + for automatic schema generation. + + + - abstract (optional): Used to mark abstract superclasses in - <union-subclass> hierarchies. + subselect (optional): Maps an immutable and read-only entity to a database sub-select. + This is useful if you want to have a view instead of a base table. See + for more information. + + + + + schema-action (optional): Specifies which schema actions should be generated for the + class table by the schema export tool. Valid values are none, drop, + update, export, validate, + all and any combination of them separated by commas (,). + Not specifying it is treated as all. See . + + + + + rowid and node (optional): These attributes have no + usage in NHibernate. The node attribute is present on many more mapping elements, and + has no usage on them too. It will be omitted from the documentation of these other elements. @@ -324,7 +396,8 @@ declare implementing classes of that interface using the <subclass> element. You may persist any inner class. You should specify the class name using the standard form ie. Eg.Foo+Bar, Eg. - Due to an HQL parser limitation inner classes can not be used in queries in NHibernate 1.0. + Due to an HQL parser limitation inner classes can not be used in queries in NHibernate, unless + assigning to them an entity-name without the + character. @@ -333,10 +406,15 @@ - The optional proxy attribute enables lazy initialization of persistent - instances of the class. NHibernate will initially return proxies which implement - the named interface. The actual persistent object will be loaded when a method of the - proxy is invoked. See "Proxies for Lazy Initialization" below. + The optional proxy attribute enables customization of the generated proxy + for lazy initialization of persistent instances of the class: by default, the proxy derives + from the class. Specifying an interface causes the proxy to implement it and to use + System.Object as its base class. This enables proxifying a sealed class + or a class having non virtual members. The specified interface should declare all the public + members of the persistent class. On ISession.Load and on + many-to-one associations, NHibernate will initially return proxies. The + actual persistent object will be loaded when a method or property of the proxy is invoked. + See . Implicit polymorphism means that instances of the class will be returned @@ -372,7 +450,8 @@ Use of select-before-update will usually decrease performance. It is very - useful to prevent a database update trigger being called unnecessarily. + useful to prevent a database update trigger being called unnecessarily if you reattach a graph + of detached instances to an ISession. @@ -406,9 +485,6 @@ columns for optimistic locking with NHibernate. This is the optimal strategy with respect to performance and is the only strategy that correctly handles modifications made outside of the session (ie. when ISession.Update() is used). - Keep in mind that a version or timestamp property should never be null, no matter - what unsaved-value strategy, or an instance will be detected as - transient. @@ -425,7 +501,8 @@ An alternative to mapping a class to table or view columns is to map a query. For that, we use the <subselect> element, which is mutually exclusive with <subclass>, <joined-subclass> - and <union-subclass>. + and <union-subclass>. The subselect may also be specified as a + <class> attribute. The content of the subselect element is a SQL query: @@ -451,7 +528,12 @@ SELECT cat.ID, cat.NAME, cat.SEX, cat.MATE FROM cat ]]> </subselect> -<syncronize table="cat"/> +<synchronize table="cat"/> + + + This ensures that auto-flush happens correctly and that queries against the derived entity + do not return stale data. + You then still have to declare the class id and properties. @@ -471,20 +553,24 @@ - - - - - + + + + + + + - - + name="propertyName" + type="typeName" + length="typeLength" + column="columnName" + unsaved-value="any|none|null|undefined|idValue" + access="field|property|nosetter|className" + generator="generatorClass"> + + ]]> @@ -498,38 +584,53 @@ + + length (optional): If the type takes a length and does not + already specify it, its length. + + + column (optional - defaults to the property name): The name of the primary key column. - + - unsaved-value (optional - defaults to a "sensible" value): + unsaved-value (optional - defaults to a "sensible" value): An identifier property value that indicates that an instance is newly instantiated (unsaved), distinguishing it from transient instances that were saved or loaded in a previous session. - + access (optional - defaults to property): The strategy NHibernate should use for accessing the property value. + + + generator: The name of a generator class to use for generating + unique identifiers for instances of the persistent class. See the + generator element. Specifying + either the attribute or the element is required. The attribute takes precedence over + the element. + + - + If the name attribute is missing, it is assumed that the class has no identifier property. - The unsaved-value attribute is almost never needed in NHibernate 1.0. + The unsaved-value attribute is almost never needed in NHibernate. - + There is an alternative <composite-id> declaration to allow access to legacy data with composite keys. We strongly discourage its use for anything else. @@ -547,11 +648,11 @@ using <param> elements. - - - uid_table - next_hi_value_column - + + + uid_table + next_hi_value_column + ]]> @@ -559,7 +660,7 @@ attribute directly on the <id> element, as follows: - ]]> + ]]> All generators implement the interface NHibernate.Id.IIdentifierGenerator. @@ -579,12 +680,24 @@ + counter, vm + + + generates identifiers of 64bits integral type constructed from the system + time and a counter value. + Do not use in a cluster. May generate colliding identifiers in + a bit less than one year. + + + + identity - supports identity columns in DB2, MySQL, MS SQL Server and Sybase. The identifier - returned by the database is converted to the property type using - Convert.ChangeType. Any integral property type is thus supported. + supports identity columns in DB2, MySQL, MS SQL Server, Sybase and some other systems. + The identifier returned by the database is converted to the property type using + Convert.ChangeType. Any integral property type is thus supported. + See . @@ -592,10 +705,11 @@ sequence - uses a sequence in DB2, PostgreSQL, Oracle or a generator + uses a sequence in DB2, PostgreSQL, Oracle and some other systems, or a generator in Firebird. The identifier returned by the database is converted to the property type using Convert.ChangeType. Any integral property type is thus supported. + See . @@ -607,11 +721,8 @@ given a table and column (by default hibernate_unique_key and next_hi respectively) as a source of hi values. The hi/lo algorithm generates identifiers that are unique only for a particular database. Do not - use this generator with a user-supplied connection. - - - You can use the "where" parameter to specify the row to use in a table. This is useful - if you want to use a single table for your identifiers, with different rows for each table. + use this generator with an user-supplied connection. See + . @@ -620,7 +731,7 @@ uses a hi/lo algorithm to efficiently generate identifiers of any integral type, - given a named database sequence. + given a named database sequence. See . @@ -630,7 +741,7 @@ uses System.Guid and its ToString(string format) method to generate identifiers of type string. The length of the string returned depends on the - configured format. + configured format. See . @@ -639,7 +750,7 @@ uses a new System.Guid to create a byte[] that is - converted to a string. + converted to a string. See . @@ -647,7 +758,8 @@ guid - uses a new System.Guid as the identifier. + uses a new System.Guid as the identifier. It is not equivalent + to the Hibernate guid generator. See . @@ -658,7 +770,15 @@ uses the algorithm to generate a new System.Guid described by Jimmy Nilsson in this - article. + article. See also . + + + + + guid.native + + + uses the database server side Guid function. @@ -669,6 +789,7 @@ picks identity, sequence or hilo depending upon the capabilities of the underlying database. + See . @@ -678,6 +799,17 @@ lets the application to assign an identifier to the object before Save() is called. + See . + + + + + select + + + retrieves a primary key, assigned by a database trigger, by selecting the row by some + unique key and retrieving the primary key value. + See . @@ -685,11 +817,50 @@ foreign - uses the identifier of another associated object. Usually used in conjunction + uses the identifier of another associated object. It is usually used in conjunction with a <one-to-one> primary key association. + + sequence-identity + + + a generator which combines sequence generation with immediate retrieval + by attaching an output parameter to the SQL command. + In this respect it works much like ANSI-SQL identity generation. + + + + + trigger-identity + + + a generator which uses an output parameter to return the identifier generated by the insert + on database server side. + + + + + enhanced-sequence + + + uses a sequence with database supporting them, otherwise uses a table for emulating the sequence. + See . Supports + . + + + + + enhanced-table + + + uses a table like the hilo generator, but can handle multiple increment values + per table. See . Supports + . + + + @@ -704,25 +875,58 @@ The second uses an Oracle-style sequence (where supported). + + Unfortunately, you can't use hilo when supplying your own + DbConnection to NHibernate. NHibernate must be able to + fetch the "hi" value in a new transaction. + + - - hi_value - next_value - 100 - + + tableName + columnName + schemaName + catalogName + 100 + arbitraryWhereClause + ]]> + + table defaults to hibernate_unique_key, + column defaults to next_hi, + and max_lo defaults to 32767. + schema, catalog and where + are optional and have no default value. + + + + You can use the optional where parameter to specify the row to use in a table. This is + useful if you want to use a single table for your identifiers, with different rows for each table. Do not + include the where keyword in its value. + This is not handled by NHibernate schema generation tooling. + + - - hi_value - 100 - + + hi_valuehibernate_sequence + schemaName + catalogName + 100 + arbitrarySqlFragment + ]]> - Unfortunately, you can't use hilo when supplying your own - DbConnection to NHibernate. NHibernate must be able to - fetch the "hi" value in a new transaction. + sequence defaults to hibernate_sequence, + and max_lo defaults to 9. + schema, catalog and parameters + are optional and have no default value. + + + + You can use the optional parameters parameter to specify some SQL to be + appended to the create sequence DDL. @@ -730,10 +934,10 @@ UUID Hex Algorithm - - format_value - separator_value - + + format_value + separator_value + ]]> @@ -777,15 +981,15 @@ - - uid_sequence - + + uid_sequence + ]]> - - + + ]]> - + For cross-platform development, the native strategy will choose from the identity, sequence and @@ -793,7 +997,7 @@ underlying database. - + Assigned Identifiers @@ -804,24 +1008,92 @@ keys with business meaning (almost always a terrible design decision). - Due to its inherent nature, entities that use this generator cannot be saved - via the ISession's SaveOrUpdate() method. Instead you have to explicitly specify to - NHibernate if the object should be saved or updated by calling either the - Save() or Update() method of the ISession. + Due to its inherent nature, entities that use this generator may, when saved via + the ISession's SaveOrUpdate() method, cause NHibernate to query the database for + checking if the entity exist or not. + + + To avoid this, either: + + + + + ensure that the identifier unsaved-value is not defined or is set + to undefined, and define an unsaved-value on + a <version> or <timestamp> property + mapping for the class. (Depending on the version type, its default + unsaved-value will generally already be suitable.) + + + + + specify to NHibernate if the object should be saved or updated by calling either the + Save() or Update() method of the ISession. + + + + + set unsaved-value="none" and explicitly Save() + newly instantiated objects. + + + + + set unsaved-value="any" and explicitly Update() + previously persistent objects. + + + + + implement IInterceptor.IsTransient() for providing your own strategy + for distinguishing newly instantiated objects. See + . + + + + + For assigned identifiers, unsaved-value default value is + undefined. + + + + + Primary keys assigned by triggers + + NHibernate does not generate DDL with triggers. It is for legacy schemas only. + + + + + socialSecurityNumber + +]]> + + + In the above example, there is a unique valued property named + socialSecurityNumber. It is defined by the class, as a property. + And a surrogate key named person_id has its value generated by a trigger. Its value + will be retrieved by querying the entity table filtered by the key + property. + + + + If the class maps a natural id, + key can be omitted. The natural id will be used when + key is omitted. Enhanced identifier generators - Starting with NHibernate release 3.3.0, there are 2 new generators which - represent a re-thinking of 2 different aspects of identifier + Starting with NHibernate release 3.3.0, there are two new generators which + represent a re-thinking of two different aspects of identifier generation. The first aspect is database portability; the second is optimization. Optimization means that you do not have to query the database for every request for a new identifier value. These two new generators are intended to take the place of some of the named - generators described above, starting in 3.3.x. However, they are - included in the current releases and can be referenced by FQN. + generators described above. The first of these new generators is NHibernate.Id.Enhanced.SequenceStyleGenerator @@ -843,13 +1115,15 @@ emulate with its table-based generators. This generator has a number of configuration parameters: - sequence_name (optional, defaults to + sequence_name (optional - defaults to hibernate_sequence): the name of the sequence - or table to be used. + or table to be used. schema and + catalog parameters can be additionally used + to qualify the sequence name. - initial_value (optional, defaults to + initial_value (optional - defaults to 1): the initial value to be retrieved from the sequence/table. In sequence creation terms, this is analogous to the clause typically named "STARTS WITH". @@ -877,23 +1151,10 @@ used to hold the value. - - prefer_sequence_per_entity (optional - - defaults to false): should we create - separate sequence for each entity that share current generator - based on its name? - - - - sequence_per_entity_suffix (optional - - defaults to _SEQ): suffix added to the name - of a dedicated sequence. - - optimizer (optional - defaults to - none): See + none if increment_size is 1): + See @@ -912,7 +1173,9 @@ table_name (optional - defaults to hibernate_sequences): the name of the table - to be used. + to be used. schema and + catalog parameters can be additionally used + to qualify the sequence name. @@ -931,7 +1194,9 @@ segment_value (optional - defaults to - default): The "segment key" value for the + default unless + prefer_entity_table_as_segment_value is + true): The "segment key" value for the segment from which we want to pull increment values for this generator. @@ -942,6 +1207,14 @@ the column size to create this segment key column. + + prefer_entity_table_as_segment_value + (optional - defaults to false): If + segment_value is not specified, whether it + should defaults to the entity table name or to + default. + + initial_value (optional - defaults to 1): The initial value to be retrieved from @@ -956,7 +1229,7 @@ optimizer (optional - defaults to - ??): See none if increment_size is 1): See . @@ -1020,14 +1293,15 @@ composite-id - - - - ...... + name="propertyName" + class="className" + unsaved-value="any|none" + access="field|property|nosetter|className" + mapped="true|false"> + + + + ... ]]> @@ -1038,8 +1312,8 @@ - - + + ]]> @@ -1053,9 +1327,33 @@ is its own identifier. There is no convenient "handle" other than the object itself. You must instantiate an instance of the persistent class itself and populate its identifier properties before you can Load() the persistent state - associated with a composite key. We will describe a much more - convenient approach where the composite identifier is implemented as a separate class - in . The attributes described below apply only + associated with a composite key. We call this approach an embedded composite identifier, + and discourage it for serious applications. + + + + + + unsaved-value (optional - default to undefined): + controls how transient instances are considered. any assumes + any transient instance is newly instantiated. In other words, the instance will be + saved (inserted in the database). none assumes any transient instance + is already persisted. In other words, the instance will be updated. + undefined does not assume anything: NHibernate may query the database + for determining if the entity is already persisted or not. + + + + + mapped (optional - defaults to false): + This attribute has no usage in NHibernate. + + + + + + A much more convenient approach is to implement the composite identifier as a separate class, + as in . The attributes described below apply only to this alternative approach: @@ -1063,7 +1361,7 @@ name (optional, required for this approach): A property of - component type that holds the composite identifier (see next section). + component type that holds the composite identifier (see ). @@ -1074,12 +1372,16 @@ - class (optional - defaults to the property type determined by - reflection): The component class used as a composite identifier (see next section). + class (optional - defaults to the property type determined by + reflection): The component class used as a composite identifier. + + The second approach, an identifier component, is recommended for almost all applications. + + @@ -1097,49 +1399,65 @@ - - - - - + + + + + + + ]]> - column (optional - defaults to class) the + column (optional - defaults to class): the name of the discriminator column. - type (optional - defaults to String) a + type (optional - defaults to String): a name that indicates the NHibernate type - force (optional - defaults to false) + length (optional): if the type takes a length and does not + already specify it, its length. + + + + + not-null (optional - defaults to true): + sets the column nullability for DDL generation. + + + + + force (optional - defaults to false): "force" NHibernate to specify allowed discriminator values even when retrieving all instances of the root class. - + - insert (optional - defaults to true) + insert (optional - defaults to true): set this to false if your discriminator column is also part of a mapped composite identifier. - + - formula (optional) an arbitrary SQL expression that is + formula (optional): an arbitrary SQL expression that is executed when a type has to be evaluated. Allows content-based discrimination. @@ -1153,13 +1471,13 @@ - The force attribute is (only) useful if the table contains rows with + The force attribute is only useful if the table contains rows with "extra" discriminator values that are not mapped to a persistent class. This will not usually be the case. - Using the formula attribute you can declare an arbitrary SQL expression + Using the formula attribute, you can declare an arbitrary SQL expression that will be used to evaluate the type of a row: @@ -1174,25 +1492,27 @@ The <version> element is optional and indicates that the table contains versioned data. This is particularly useful if you plan to - use long transactions (see below). + use long transactions (see ). - - - - - - + + + + + + + ]]> @@ -1223,15 +1543,23 @@ unsaved-value (optional - defaults to a "sensible" value): A version property value that indicates that an instance is newly instantiated (unsaved), distinguishing it from transient instances that were saved or loaded - in a previous session. (undefined specifies that the identifier - property value should be used.) + in a previous session. undefined specifies that nothing + should be assumed from the version property. The identifier check on its own + unsaved-value will take precedence, unless its own value is + undefined. generated (optional - defaults to never): Specifies that this version property value is actually generated by the database. - See the discussion of generated properties. + See the discussion of generated properties. + + + + + insert (optional - defaults to false): + This attribute has no usage in NHibernate. @@ -1241,7 +1569,7 @@ Version may be of type Int64, Int32, Int16, Ticks, Timestamp, TimeSpan, datetimeoffset, ... (or their nullable - counterparts in .NET 2.0). Any type implementing IVersionType is + counterparts in .NET 2.0 and higher). Any type implementing IVersionType is usable as a version. @@ -1259,18 +1587,20 @@ - - - - - + + + + + + ]]> @@ -1296,15 +1626,33 @@ unsaved-value (optional - defaults to null): A timestamp property value that indicates that an instance is newly instantiated (unsaved), distinguishing it from transient instances that were saved or loaded - in a previous session. (undefined specifies that the identifier - property value should be used.) + in a previous session. undefined specifies that nothing + should be assumed from the timestamp value. The identifier check on its own + unsaved-value will take precedence, unless its own value is + undefined. generated (optional - defaults to never): - Specifies that this timestamp property value is actually generated by the database. - See the discussion of generated properties. + Specifies that this timestamp property value is actually generated by the database + on insert and updates. + See the discussion of generated properties. + It should not to be confused with source value + db, which mandates NHibernate to retrieve the timestamp from the + database in a dedicated query, in order to get the new value to set in the next insert + or update. + + + + + source (optional - defaults to vm): Where should + NHibernate retrieve the timestamp value from? From the database, or from the current + runtime? Database-based timestamps incur an overhead because NHibernate must hit the + database in order to determine the "next value". It is safer to use in clustered + environments. Not all dialects are known to support the retrieval of the database's + current timestamp. Others may also be unsafe for usage in locking due to lack of + precision. @@ -1312,11 +1660,11 @@ Note that <timestamp> is equivalent to - <version type="timestamp">. + <version type="datetime">, and <timestamp source="db"> + is equivalent to <version type="dbtimestamp">. - property @@ -1327,30 +1675,44 @@ - - - + + + - - + + - - - - - + + + + + + + + + + + + ]]> @@ -1371,7 +1733,7 @@ - update, insert (optional - defaults to true) : + update, insert (optional - defaults to true): specifies that the mapped columns should be included in SQL UPDATE and/or INSERT statements. Setting both to false allows a pure "derived" property whose value is initialized from some other @@ -1387,39 +1749,89 @@ - access (optional - defaults to property): The + access (optional - defaults to property): the strategy NHibernate should use for accessing the property value. optimistic-lock (optional - defaults to true): - Specifies that updates to this property do or do not require acquisition of the - optimistic lock. In other words, determines if a version increment should occur when + specifies that updates to this property do or do not require acquisition of the + optimistic lock. In other words, determines if a version increment should occur when this property is dirty. generated (optional - defaults to never): - Specifies that this property value is actually generated by the database. - See the discussion of generated properties. + specifies that this property value is actually generated by the database. + See the discussion of generated properties. lazy (optional - defaults to false): - Specifies that this property is lazy. A lazy property is not loaded when + specifies that this property is lazy. A lazy property is not loaded when the object is initially loaded, unless the fetch mode has been overridden in a specific query. Values for lazy properties are loaded when any lazy - property of the object is accessed. + property of the object is accessed. Having lazy properties causes instances + of the entity to be loaded as proxies. Theses proxies ignore the class + proxy setting and always derives from the persistent class, + requiring its members to be overridable. - - - - - typename could be: + + + not-null (optional - defaults to false): + sets the column nullability for DDL generation. + + + + + unique (optional - defaults to false): + sets the column uniqueness for DDL generation. Use unique-key + instead if the value is unique only in combination with other properties. + + + + + unique-key (optional): + a logical name for an unique index for DDL generation. The column will be included in + the index, along with other columns sharing the same unique-key + logical name. The actual index name depends on the dialect. + + + + + index (optional): + a logical name for an index for DDL generation. The column will be included in + the index, along with other columns sharing the same index logical + name. The actual index name depends on the dialect. + + + + + length (optional): if the type takes a length and does not + already specify it, its length. + + + + + precision (optional): if the type takes a precision and does not + already specify it, its precision. + + + + + scale (optional): if the type takes a scale and does not + already specify it, its scale. + + + + + + + typeName could be: @@ -1473,7 +1885,7 @@ 4 in that order. However, this is not always enough. In certain cases you will still need the type attribute. (For example, to distinguish between NHibernateUtil.DateTime and - NHibernateUtil.Timestamp, or to specify a custom type.) + NHibernateUtil.UtcDateTime, or to specify a custom type.) @@ -1520,6 +1932,15 @@ + + backfield + + + NHibernate will access the field of an auto-property directly. + This can be used when a property's setter is not accessible. + + + nosetter @@ -1534,7 +1955,25 @@ - ClassName + readonly + + + Access the mapped property through a Property get to get the value + and do nothing to set the value. This is useful to allow calculated properties in the + domain that will never be recovered from the DB but can be used for querying. + + + + + noop / none + + + Used to declare properties not represented at the poco level. + + + + + className If NHibernate's built in access strategies are not what is needed for your situation @@ -1643,6 +2082,29 @@ + + A powerful feature is derived properties. These properties are by definition read-only. The property value is computed at + load time. You declare the computation as an SQL expression. This then translates to a SELECT clause + subquery in the SQL query that loads an instance: + + + ]]> + + + You can reference the entity table by not declaring an alias on a particular column. This would be + customerId in the given example. You can also use the nested <formula> mapping + element if you do not want to use the attribute. + + + + The nested <column> mapping element can also be used instead of the column + attribute. + + @@ -1651,7 +2113,7 @@ An ordinary association to another persistent class is declared using a many-to-one element. The relational model is a - many-to-one association. (It's really just an object reference.) + many-to-one association. (It is really just an object reference.) @@ -1661,29 +2123,45 @@ - - + + + - + + + + + + + + ]]> @@ -1693,7 +2171,8 @@ - column (optional): The name of the column. + column (optional): The name of the column. This can also be + specified by nested <column> element(s). @@ -1712,36 +2191,42 @@ fetch (optional - defaults to select): Chooses between outer-join fetching or sequential select fetching. + join takes precedence over the lazy + attribute and causes the association to be eagerly fetched. - + - update, insert (optional - defaults to true) - specifies that the mapped columns should be included in SQL UPDATE + lazy (optional - defaults to proxy): + By default, single point associations are proxied. lazy="no-proxy" + specifies that the property should be fetched lazily when the instance property is first + accessed. It works similarly to lazy properties, and causes the entity owning the + association to be proxied instead of the association. lazy="false" + specifies that the association will be eagerly fetched. + + + + + update, insert (optional - defaults to true): + Specifies that the mapped columns should be included in SQL UPDATE and/or INSERT statements. Setting both to false allows a pure "derived" association whose value is initialized from some other property that maps to the same column(s) or by a trigger or other application. - + - property-ref: (optional) The name of a property of the associated + property-ref (optional): The name of a property of the associated class that is joined to this foreign key. If not specified, the primary key of the associated class is used. - + access (optional - defaults to property): The strategy NHibernate should use for accessing the property value. - - - unique (optional): Enable the DDL generation of a unique - constraint for the foreign-key column. - - optimistic-lock (optional - defaults to true): @@ -1753,66 +2238,118 @@ not-found (optional - defaults to exception): - Specifies how foreign keys that reference missing rows will be handled: + Specifies how foreign keys that reference missing rows will be handled. ignore will treat a missing row as a null association. + + + entity-name (optional): The entity name of the associated class. + + + + + formula (optional): An SQL expression that defines the value for + a computed foreign key. + + + + + not-null (optional - defaults to false): Enables + the DDL generation of a nullability constraint for the foreign key column. + + + + + unique (optional - defaults to false): Enables + the DDL generation of an unique constraint for the foreign-key column. + + + + + unique-key (optional): + A logical name for an unique index for DDL generation. The column will be included in + the index, along with other columns sharing the same unique-key + logical name. The actual index name depends on the dialect. + + + + + index (optional): + A logical name for an index for DDL generation. The column will be included in + the index, along with other columns sharing the same index logical + name. The actual index name depends on the dialect. + + + + + foreign-key (optional): Specifies the name of the foreign key + constraint for DDL generation. + + + + + outer-join (optional): This attribute is obsoleted in favor of + fetch. auto is equivalent to not specifying + fetch, true is equivalent to + join and false is equivalent to + select. This obsolete attribute also appears on other elements, + with the same usage. It will be omitted from the documentation of these other + elements. + + - The cascade attribute permits the following values: - all, save-update, delete, - delete-orphan, all-delete-orphan and - none. Setting a value other than none - will propagate certain operations to the associated (child) object. - See "Lifecycle Objects" below. + Setting a value of the cascade attribute to any meaningful value other than + none will propagate certain operations to the associated object. The + meaningful values are divided into three categories. First, basic operations, which include: + persist, merge, delete, + save-update, evict, replicate, + lock and refresh; second, special values: + delete-orphan; and third, all comma-separated combinations of operation names: + cascade="persist,merge,evict" or cascade="all,delete-orphan". + See . - The fetch attribute accepts two different values: + Here is an example of a typical many-to-one declaration: - - - - join Fetch the association using an outer join - - - - - select Fetch the association using a separate query - - - + ]]> - A typical many-to-one declaration looks as simple as + The property-ref attribute should only be used for mapping legacy data where a + foreign key refers to a unique key of the associated table other than the primary key. This is a + complicated and confusing relational model. For example, if the Product class had a unique serial + number that is not the primary key, mapped as below: - ]]> - + ]]> + - The property-ref attribute should only be used for mapping legacy - data where a foreign key refers to a unique key of the associated table other than - the primary key. This is an ugly relational model. For example, suppose the - Product class had a unique serial number, that is not the primary - key. (The unique attribute controls NHibernate's DDL generation with - the SchemaExport tool.) + The unique attribute controls NHibernate's DDL generation with the SchemaExport tool. Then the + mapping for OrderItem might use: - ]]> + ]]> - Then the mapping for OrderItem might use: + This is not encouraged, however. + + + + If the referenced unique key comprises multiple properties of the associated entity, you should map + the referenced properties inside a named <properties> element. - ]]> - - This is certainly not encouraged, however. + If the referenced unique key is the property of a component, you can specify a property path: + ]]> + @@ -1832,15 +2369,23 @@ + + + + ]]> @@ -1856,17 +2401,18 @@ - cascade (optional) specifies which operations should + cascade (optional): Specifies which operations should be cascaded from the parent object to the associated object. - constrained (optional) specifies that a foreign key constraint - on the primary key of the mapped table references the table of the associated - class. This option affects the order in which Save() and - Delete() are cascaded (and is also used by the schema export - tool). + constrained (optional - default to false): + Specifies that a foreign key constraint on the primary key of the mapped table + references the table of the associated class. This option affects the order in + which Save() and Delete() are cascaded, + and determines whether the association can be proxied. It is also used by the + schema export tool. @@ -1877,17 +2423,48 @@ - property-ref: (optional) The name of a property of the associated class - that is joined to the primary key of this class. If not specified, the primary key of - the associated class is used. + lazy (optional - defaults to proxy): + By default, single point associations are proxied. lazy="no-proxy" + specifies that the property should be fetched lazily when the instance property is first + accessed. It works similarly to lazy properties, and causes the entity owning the + association to be proxied instead of the association. lazy="false" + specifies that the association will be eagerly fetched. Note that if + constrained="false", proxying the association is impossible and + NHibernate will eagerly fetch the association. + + property-ref: (optional): The name of a property of the associated class + that is joined to the primary key of this class (or to the formula of + this association). If not specified, the primary key of the associated class is used. + + + access (optional - defaults to property): The strategy NHibernate should use for accessing the property value. + + + formula (optional): Almost all one-to-one associations map to the primary + key of the owning entity. If this is not the case, you can specify another column or expression + to join on using an SQL formula. This can also be specified by nested + <formula> element(s). + + + + + entity-name (optional): The entity name of the associated class. + + + + + foreign-key (optional): Specifies the name of the foreign key + constraint for DDL generation. + + @@ -1962,9 +2539,9 @@ natural-id - - - ...... + + + ... ]]> @@ -1975,16 +2552,21 @@ NHibernate will generate the necessary unique key and nullability constraints, and your mapping will be more self-documenting. - + + + The <natural-id> element can only appear before the other + properties, including version. + + We strongly recommend that you implement Equals() and GetHashCode() to compare the natural key properties of the entity. - + This mapping is not intended for use with entities with natural primary keys. - + @@ -1993,9 +2575,9 @@ - + - + component, dynamic-component @@ -2003,7 +2585,7 @@ The <component> element maps properties of a child object to columns of the table of a parent class. Components may, in turn, declare their own properties, components or collections. See - "Components" below. + . @@ -2014,18 +2596,22 @@ + + - + - - - ........ + + + ... ]]> @@ -2041,14 +2627,14 @@ - insert: Do the mapped columns appear in SQL - INSERTs? + insert (optional - defaults to true): + Do the mapped columns appear in SQL INSERTs? - update: Do the mapped columns appear in SQL - UPDATEs? + update (optional - defaults to true): + Do the mapped columns appear in SQL UPDATEs? @@ -2065,6 +2651,20 @@ this property is dirty. + + + lazy (optional - defaults to false): Specifies + that this component should be fetched lazily when the instance property is first + accessed. For more informations, see lazy on + property element. + + + + + unique (optional - defaults to false): Specifies + that an unique constraint exists upon all mapped columns of the component. + + @@ -2081,8 +2681,8 @@ The <dynamic-component> element allows an IDictionary - or IDictionary<string, object>to be mapped as a component, where the property - names refer to keys of the dictionary. + or IDictionary<string, object> to be mapped as a component, where the + property names refer to keys of the dictionary. See . @@ -2109,15 +2709,15 @@ - - - - ........ + name="logicalName" + insert="true|false" + update="true|false" + optimistic-lock="true|false" + unique="true|false"> + + + + ... ]]> @@ -2130,15 +2730,15 @@ - insert: do the mapped columns appear in - SQL INSERTs? + insert (optional - defaults to true): + do the mapped columns appear in SQL INSERTs? - update: do the mapped columns appear in - SQL UPDATEs? + update (optional - defaults to true): + do the mapped columns appear in SQL UPDATEs? @@ -2168,12 +2768,12 @@ - - - - - - + + + + + + ]]> @@ -2183,9 +2783,9 @@ - - - + + + ]]> @@ -2198,7 +2798,7 @@ subclass - Finally, polymorphic persistence requires the declaration of each subclass of + Polymorphic persistence requires the declaration of each subclass of the root persistent class. For the (recommended) table-per-class-hierarchy mapping strategy, the <subclass> declaration is used. @@ -2211,16 +2811,14 @@ - - - - ..... + name="className" + discriminator-value="discriminatorValue" + extends="superclassName" + ...> + + + + ... ]]> @@ -2237,14 +2835,20 @@ - proxy (optional): Specifies a class or interface to use for - lazy initializing proxies. + extends (optional if the <subclass> + element is nested into its superclass mapping declaration): Specifies the name of + a mapped class as the superclass for the subclass. - lazy (optional, defaults to true): Setting - lazy="false" disables the use of lazy fetching. + Many attributes available on the <class> mapping element + are also available on <subclass> with the same usage: + proxy, dynamic-update, + dynamic-insert, select-before-update, + persister, batch-size, lazy, + entity-name, abstract. See + . @@ -2261,36 +2865,36 @@ For information about inheritance mappings, see . - + - + joined-subclass - Alternatively, a subclass that is persisted to its own table (table-per-subclass - mapping strategy) is declared using a <joined-subclass> - element. + Each subclass can also be mapped to its own table. This is called the table-per-subclass + mapping strategy. An inherited state is retrieved by joining with the table of the + superclass. To do this you use the <joined-subclass> element. - - - + + + + + name="className" + table="tableName" + extends="superclassName" + ...> - + - - - ..... + + + ... ]]> @@ -2300,15 +2904,27 @@ - proxy (optional): Specifies a class or interface to use - for lazy initializing proxies. + table (optional - defaults to the unqualified subclass name): + The name of the subclass table. - lazy (optional): Setting lazy="true" is a shortcut - equivalent to specifying the name of the class itself as the proxy - interface. + extends (optional if the <joined-subclass> + element is nested into its superclass mapping declaration): Specifies the name of + a mapped class as the superclass for the subclass. + + + + + Many attributes available on the <class> mapping element + are also available on <joined-subclass> with the same usage: + schema, catalog, proxy, + subselect, dynamic-update, + dynamic-insert, select-before-update, + persister, batch-size, lazy, + entity-name, abstract, check, + schema-action. See . @@ -2320,33 +2936,33 @@ <key> element. The mapping at the start of the chapter would be re-written as: - - + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + ]]> @@ -2372,30 +2988,20 @@ - - - - + + + + - - - - ..... + name="className" + table="tableName" + extends="superclassName" + ...> + + + + ... ]]> @@ -2405,19 +3011,27 @@ - table: The name of the subclass table. + table (optional - defaults to the unqualified subclass name): + The name of the subclass table. - proxy (optional): Specifies a class or interface to use - for lazy initializing proxies. + extends (optional if the <union-subclass> + element is nested into its superclass mapping declaration): Specifies the name of + a mapped class as the superclass for the subclass. - lazy (optional, defaults to true): Setting - lazy="false" disables the use of lazy fetching. + Many attributes available on the <class> mapping element + are also available on <union-subclass> with the same usage: + schema, catalog, proxy, + subselect, dynamic-update, + dynamic-insert, select-before-update, + persister, batch-size, lazy, + entity-name, abstract, check. + See . @@ -2448,18 +3062,22 @@ + + + table="tableName" + schema="owner" + catalog="catalog" + fetch="join|select" + inverse="true|false" + optional="true|false" + subselect="SQL expression"> - + - - ... + + ... ]]> @@ -2470,12 +3088,17 @@ - schema (optional): Override the schema name specified by + schema (optional): Overrides the schema name specified by the root <hibernate-mapping> element. - + + catalog (optional): Overrides the catalog name specified by + the root <hibernate-mapping> element. + + + fetch (optional - defaults to join): If set to join, the default, NHibernate will use an inner join @@ -2488,20 +3111,27 @@ superclasses. - + inverse (optional - defaults to false): If enabled, NHibernate will not try to insert or update the properties defined by this join. - + optional (optional - defaults to false): If enabled, NHibernate will insert a row only if the properties defined by this join are non-null and will always use an outer join to retrieve the properties. + + + subselect (optional): Maps an immutable and read-only join to + a database sub-select. This is useful if you want to have a view instead of a + table. See for more information. + + @@ -2510,9 +3140,7 @@ table (while preserving value type semantics for all properties): - - + ... @@ -2532,11 +3160,145 @@ + + key + + + The <key> element has featured a few times within this guide. It appears + anywhere the parent mapping element defines a join to a new table that references the primary key + of the original table. It also defines the foreign key in the joined table: + + + + + + + + + + + + + ]]> + + + + + column: the name of the foreign key column. This can also be specified + by nested <column> element(s). + + + + + on-delete (optional - defaults to noaction): specifies + whether the foreign key constraint has database-level cascade delete enabled. + + + + + property-ref (optional): specifies that the foreign key refers to columns + that are not the primary key of the original table. It is provided for legacy data. + + + + + not-null (optional): specifies that the foreign key columns are not nullable. + This is implied whenever the foreign key is also part of the primary key. + + + + + update (optional): specifies that the foreign key should never be updated. + This is implied whenever the foreign key is also part of the primary key. + + + + + unique (optional): specifies that the foreign key should have a unique + constraint. This is implied whenever the foreign key is also the primary key. + + + + + foreign-key (optional): specifies the name of the foreign key + constraint for DDL generation. + + + + + + + For systems where delete performance is important, we recommend that all keys should be defined + on-delete="cascade". NHibernate uses a database-level + ON CASCADE DELETE constraint, instead of many individual DELETE + statements. Be aware that this feature bypasses NHibernate's usual optimistic locking strategy for + versioned data. + + + + The not-null and update attributes are useful when mapping an + unidirectional one-to-many association. If you map an unidirectional one-to-many association to a + non-nullable foreign key, you must declare the key column using + <key not-null="true">. + + + + + + column and formula elements + + + Mapping elements which accept a column attribute will alternatively accept a + <column> subelement. Likewise, <formula> is an + alternative to the formula attribute. For example: + + + ]]> + + SQL expression]]> + + + Most of the attributes on column provide a means of tailoring the DDL during + automatic schema generation. See . + + + + The column and formula elements can even be combined within + the same property or association mapping to express, for example, exotic join conditions. + + + + + 'MAILING' +]]> + + + map, set, list, bag - Collections are discussed later. + Collections are discussed in . @@ -2549,17 +3311,17 @@ explicitly, rather than relying upon auto-import="true". You may even import classes and interfaces that are not explicitly mapped. - + ]]> - + ]]> @@ -2576,7 +3338,147 @@ - + + + + + any + + + There is one more type of property mapping. The <any> mapping element defines a + polymorphic association to classes from multiple tables. This type of mapping requires more than one + column. The first column contains the type of the associated entity. The remaining columns contain the + identifier. It is impossible to specify a foreign key constraint for this kind of association. This is + not the usual way of mapping polymorphic associations and you should use this only in special cases. For + example, for audit logs, user session data, etc. + + + + + +]]> + + + The meta-type attribute allows the application to specify a custom type that maps + database column values to persistent classes that have identifier properties of the type specified by + id-type. If the meta-type returns instances of System.Type, + nothing else is required. On the other hand, if it is a basic type like String or + Char, you must specify the mapping from values to classes. + + + + + + + + +]]> + + + + + + + + + + + + + + + + + + + ... + + + ... +]]> + + + + name: the property name. + + + + + id-type: the identifier type. + + + + + meta-type (optional - defaults to Type): a type that + maps System.Type to a single database column or, alternatively, a type + that is allowed for a discriminator mapping. + + + + + cascade (optional - defaults to none): the cascade style. + + + + + access (optional - defaults to property): the strategy + Hibernate uses for accessing the property value. + + + + + optimistic-lock (optional - defaults to true): specifies + that updates to this property either do or do not require acquisition of the optimistic lock. + It defines whether a version increment should occur if this property is dirty. + + + + + lazy (optional - defaults to false): specifies that this + property should be fetched lazily when the it is first accessed. For more informations, see + lazy on + property element. + + + + + update (optional - defaults to true): + Do the mapped columns appear in SQL UPDATEs? + + + + + insert (optional - defaults to true): + Do the mapped columns appear in SQL INSERTs? + + + + + index (optional): + a logical name for an index for DDL generation. The column will be included in + the index, along with other columns sharing the same index logical + name. The actual index name depends on the dialect. + + + + + + + Do not confuse <meta-value> elements with <meta> + elements. <meta> elements have no functionnal impact on + <any>, see for more information on them. + + @@ -2624,6 +3526,18 @@ user-defined classes with persistent state are entities. A component is a user defined class with value semantics. + + + The challenge is to map the .Net type system, and the developers' definition of + entities and value types, to the SQL/database type system. The bridge between both + systems is provided by NHibernate. For entities, <class>, + <subclass> and so on are used. For value types we use + <property>, <component>, etc., + that usually have a type attribute. The value of this attribute is the name of a + NHibernate mapping type. NHibernate provides a range of mappings for standard .Net + value types out of the box. You can write your own mapping types and implement + your own custom conversion strategies. + @@ -3058,8 +3972,8 @@ - - + + ]]> @@ -3123,107 +4037,40 @@ - - Any type mappings - - - There is one further type of property mapping. The <any> mapping element - defines a polymorphic association to classes from multiple tables. This type of mapping always - requires more than one column. The first column holds the type of the associated entity. - The remaining columns hold the identifier. It is impossible to specify a foreign key constraint - for this kind of association, so this is most certainly not meant as the usual way of mapping - (polymorphic) associations. You should use this only in very special cases (eg. audit logs, - user session data, etc). - - - - - -]]> - - - The meta-type attribute lets the application specify a custom type that - maps database column values to persistent classes which have identifier properties of the - type specified by id-type. If the meta-type returns instances of - System.Type, nothing else is required. On the other hand, if it is - a basic type like String or Char, you must - specify the mapping from values to classes. - + - - - - - - -]]> + + Mapping a class more than once + + It is possible to provide more than one mapping for a particular persistent class. In this case, + you must specify an entity name to disambiguate between instances of the two + mapped entities. By default, the entity name is the same as the class name. NHibernate lets you + specify the entity name when working with persistent objects, when writing queries, or when + mapping associations to the named entity. + - - - - - - - - - - - - - ..... - - - ..... -]]> - - - - name: the property name. - - - - - id-type: the identifier type. - - - - - meta-type (optional - defaults to Type): - a type that maps System.Type to a single database column - or, alternatively, a type that is allowed for a discriminator mapping. - - - - - cascade (optional - defaults to none): - the cascade style. - - - - - access (optional - defaults to property): The - strategy NHibernate should use for accessing the property value. - - - - - optimistic-lock (optional - defaults to true): - Specifies that updates to this property do or do not require acquisition of the - optimistic lock. In other words, define if a version increment should occur if this - property is dirty. - - - - + + ... + + + + + + + + ... + +]]> - + + Associations are now specified using entity-name instead of + class. + @@ -3237,7 +4084,9 @@ - + + + ... ]]> @@ -3256,15 +4105,16 @@ mappings in separate mapping documents, directly beneath hibernate-mapping. This allows you to extend a class hierarchy just by adding a new mapping file. You must specify an extends attribute in the subclass mapping, naming a previously - mapped superclass. Use of this feature makes the ordering of the mapping documents important! + mapped superclass. - - - + + + + ]]> @@ -3282,9 +4132,9 @@ Properties marked as generated must additionally be non-insertable and non-updatable. - Only versions, - timestamps, and - simple properties can be marked as + Only versions, + timestamps, and + simple properties can be marked as generated. @@ -3295,9 +4145,9 @@ insert - states that the given property value is generated on insert, but is not regenerated on subsequent updates. Things like created-date would fall into this category. Note that even though - version and - timestamp properties can - be marked as generated, this option is not available there... + version and + timestamp properties can + be marked as generated, this option is not available for them. always - states that the property value is generated both @@ -3308,17 +4158,16 @@ Auxiliary Database Objects - Allows CREATE and DROP of arbitrary database objects, in conjunction with - NHibernate's schema evolution tools, to provide the ability to fully define - a user schema within the NHibernate mapping files. Although designed specifically - for creating and dropping things like triggers or stored procedures, really any - SQL command that can be run via a DbCommand.ExecuteNonQuery() - method is valid here (ALTERs, INSERTS, etc). There are essentially two modes for - defining auxiliary database objects. + Auxiliary database objects allow CREATE and DROP of arbitrary database objects. In + conjunction with NHibernate's schema evolution tools, they have the ability to fully + define a user schema within the NHibernate mapping files. Although designed specifically + for creating and dropping things like triggers or stored procedures, any SQL command + that can be run via a DbCommand.ExecuteNonQuery() method is valid + (for example, ALTERs, INSERTS, etc.). There are essentially two modes for defining + auxiliary database objects: - The first mode is to explicitly list the CREATE and DROP commands out in the mapping - file: + The first mode is to explicitly list the CREATE and DROP commands in the mapping file: ... @@ -3328,7 +4177,7 @@ ]]> - The second mode is to supply a custom class which knows how to construct the + The second mode is to supply a custom class that constructs the CREATE and DROP commands. This custom class must implement the NHibernate.Mapping.IAuxiliaryDatabaseObject interface. @@ -3367,4 +4216,47 @@ ]]> + + Meta data + + + You may declare additional metadata in your mappings by using the meta element. This element + can be added to the main mapping elements. + + + + + + + + + metaData]]> + + + + attribute: The name of the metadata. + + + + + inherit (optional - defaults to true): + Whether the metadata is inherited by mapping sub-elements or not. + + + + + The text content of the meta element is its data. + + + + + + + The metadata can be retrieved at runtime from the . + + + diff --git a/doc/reference/modules/collection_mapping.xml b/doc/reference/modules/collection_mapping.xml index 62fa5525877..e2f13962b58 100644 --- a/doc/reference/modules/collection_mapping.xml +++ b/doc/reference/modules/collection_mapping.xml @@ -11,9 +11,9 @@ Parts { get; set; } = new HashSet(); + public virtual ISet Parts { get; set; } = new HashSet(); - public string SerialNumber { get; set; } + public virtual string SerialNumber { get; set; } }]]> @@ -38,7 +38,7 @@ kittens = new HashSet(); kittens.Add(kitten); cat.Kittens = kittens; @@ -64,32 +64,20 @@ HashSet hs = (HashSet) cat.Kittens; //Error!]]> Collection instances are distinguished in the database by a foreign key to - the owning entity. This foreign key is referred to as the - collection key . The collection key is mapped by - the <key> element. + the owning entity. The collection key is mapped by + the <key> element. Collections may contain almost any other NHibernate type, including all basic types, - custom types, entity types and components. This is an important definition: An object - in a collection can either be handled with "pass by value" semantics (it therefore - fully depends on the collection owner) or it can be a reference to another entity - with an own lifecycle. Collections may not contain other collections. The contained type - is referred to as the collection element type. Collection elements - are mapped by <element>, <composite-element>, - <one-to-many>, <many-to-many> or - <many-to-any>. The first two map elements with value semantics, - the other three are used to map entity associations. + custom types, entity types and components. See . - All collection types except ISet and bag have an index - column - a column that maps to an array or IList index or - IDictionary key. The index of an IDictionary may be of any - basic type, an entity type or even a composite type (it may not be a collection). The - index of an array or list is always of type Int32. Indexes are - mapped using <index>, <index-many-to-many>, - <composite-index> or <index-many-to-any>. + All collection types except ISet and bag have an index + column - a column that maps to an array or IList index or + IDictionary key. See for more + information. @@ -105,14 +93,28 @@ HashSet hs = (HashSet) cat.Kittens; //Error!]]> Mapping a Collection - Collections are declared by the - <set>, + The NHibernate mapping element used for mapping a collection depends upon the type of interface. + By example, a <set> element is used for mapping properties of type + ISet. + + + + + + + + +]]> + + + Apart from + <set>, there is also <list>, <map>, <bag>, <array> and - <primitive-array> elements. - <map> is representative: + <primitive-array> mapping elements. + The <map> element is representative: @@ -131,116 +133,184 @@ HashSet hs = (HashSet) cat.Kittens; //Error!]]> + + + + + + + - - - - + mutable="true|false" + subselect="SQL expression" + check="arbitrary sql check condition" + persister="persisterClass" + collection-type="collectionClass" + outer-join="auto|true|false" + generic="true|false"> + + + + ]]> - name the collection property name + name: the collection property name. - table (optional - defaults to property name) the - name of the collection table (not used for one-to-many associations) + table (optional - defaults to property name): the + name of the collection table. It is not used for one-to-many associations. - schema (optional) the name of a table schema to - override the schema declared on the root element + schema (optional): overrides the schema name specified by + the root <hibernate-mapping> element. - lazy (optional - defaults to true) - may be used to disable lazy fetching and specify that the association - is always eagerly fetched. Using extra fetches only the - elements that are needed - see for more information. + catalog (optional): overrides the catalog name specified by + the root <hibernate-mapping> element. - inverse (optional - defaults to false) - mark this collection as the "inverse" end of a bidirectional association + lazy (optional - defaults to true): + may be used to disable lazy fetching and specify that the association + is always eagerly fetched. Using extra fetches only the + elements that are needed - see for more information. - cascade (optional - defaults to none) - enable operations to cascade to child entities + inverse (optional - defaults to false): + marks this collection as the "inverse" end of a bidirectional association. - sort (optional) specify a sorted collection with - natural sort order, or a given comparator class + cascade (optional - defaults to none): + enables operations to cascade to child entities. - order-by (optional) specify a table column (or columns) - that define the iteration order of the IDictionary, ISet - or bag, together with an optional asc or desc + sort (optional): specifies a sorted collection with a + natural sort order, or a given comparator class. See + . - where (optional) specify an arbitrary SQL WHERE - condition to be used when retrieving or removing the collection (useful if the - collection should contain only a subset of the available data) + order-by (optional): specifies a table column (or columns) + that defines the iteration order of the IDictionary, ISet + or bag, together with an optional asc or desc. - fetch (optional) Choose between outer-join fetching and fetching - by sequential select. + where (optional): specifies an arbitrary SQL WHERE + condition to be used when retrieving or removing the collection. It is useful if the + collection should contain only a subset of the available data. - batch-size (optional, defaults to 1) specify a - "batch size" for lazily fetching instances of this collection. + fetch (optional, defaults to select): chooses between + outer-join fetching, fetching by sequential select, and fetching by sequential subselect - + see . join takes + precedence over the lazy attribute and causes the association to be + eagerly fetched. - access (optional - defaults to property): The - strategy NHibernate should use for accessing the property value. + batch-size (optional, defaults to 1): specifies a + "batch size" for lazily fetching instances of this collection. See + . - optimistic-lock (optional - defaults to true): - Species that changes to the state of the collection results in increment of the - owning entity's version. (For one to many associations, it is often reasonable to - disable this setting.) + access (optional - defaults to property): the + strategy NHibernate should use for accessing the property value. - generic (optional, obsolete): Choose between generic and non-generic - collection interfaces. But currently NHibernate only supports generic collections. + optimistic-lock (optional - defaults to true): + specifies that changes to the state of the collection results in increment of the + owning entity's version. For one to many associations, you may want to disable this + setting. + + + + + mutable (optional - defaults to true): a value of + false specifies that the elements of the collection never change. + This allows for minor performance optimization in some cases. + + + + + subselect (optional): maps an immutable and read-only collection to a + database sub-select. This is useful if you want to have a view instead of a base table. + It is not used for one-to-many associations. + + + + + check (optional): an SQL expression used to generate a multi-row check + constraint for automatic schema generation. It is not used for one-to-many associations. + + + + + persister (optional>): specifies a custom + ICollectionPersister. + + + + + collection-type (optional): the fully qualified type name of a class + implementing IUserCollectionType. + + + + + outer-join (optional): This attribute is obsoleted in favor of + fetch. auto is equivalent to not specifying + fetch, true is equivalent to + join and false is equivalent to + select. It has no value matching the subselect + fetch value. + + + + + generic (optional, defaults according to the reflected property type): + if false, NHibernate will type the collection elements as + object. Otherwise NHibernate will use reflection to determine the + element type to use. @@ -249,8 +319,8 @@ HashSet hs = (HashSet) cat.Kittens; //Error!]]> The mapping of an IList or array requires a separate table column holding the array or list index (the i in foo[i]). If your relational model doesn't - have an index column, e.g. if you're working with legacy data, use an unordered ISet - instead. This seems to put people off who assume that IList should just be a more + have an index column, use an unordered ISet instead. This seems to put people off + who assume that IList should just be a more convenient way of accessing an unordered collection. NHibernate collections strictly obey the actual semantics attached to the ISet, IList and IDictionary interfaces. IList elements don't just spontaneously rearrange themselves! @@ -269,329 +339,956 @@ HashSet hs = (HashSet) cat.Kittens; //Error!]]> - Note: Large NHibernate bags mapped with inverse="false" are inefficient and - should be avoided; NHibernate can't create, delete or update rows individually, because there is + Note: large NHibernate bags mapped with inverse="false" are inefficient and + should be avoided. NHibernate can't create, delete or update rows individually, because there is no key that may be used to identify an individual row. - + + Collection foreign keys + + + Collection instances are distinguished in the database by the foreign key of the entity that owns the + collection. This foreign key is referred to as the collection key column, or + columns, of the collection table. The collection key column is mapped by the + <key> element. + + + + There can be a nullability constraint on the foreign key column. For most collections, this is implied. + For unidirectional one-to-many associations, the foreign key column is nullable by default, so you may + need to specify not-null="true". + + + ]]> + + + The foreign key constraint can use ON DELETE CASCADE. + + + ]]> + + + See for a full definition of the + <key> element. + + + + + + Collection elements + + + Collections can contain almost any other NHibernate type, including: basic types, custom types, components + and references to other entities. This is an important distinction. An object in a collection might be + handled with "value" semantics (its life cycle fully depends on the collection owner), or it might be a + reference to another entity with its own life cycle. In the latter case, only the "link" between the two + objects is considered to be a state held by the collection. + + + + The contained type is referred to as the collection element type. Collection elements are mapped by + <element> or <composite-element>, or in the case of entity + references, with <one-to-many> or <many-to-many>. The + first two map elements with value semantics, the next two are used to map entity associations. A last one + exist for exotic entity associations, <many-to-any>, similar to + the <any> mapping element. + + + + + + Indexed collections + + + All collection mappings, except those with set and bag semantics, need an index column + in the collection table. An index column is a column that maps to an array index, or IList + index, or IDictionary key. The index of an IDictionary may be of any + basic type, mapped with <map-key>. It can be an entity reference mapped with + <map-key-many-to-many> (or in exotic cases <index-many-to-any>, + similar to the <any> mapping element), + or it can be a composite type mapped with <composite-map-key>. The index of an array or + list is always of type Int32 and is mapped using the <list-index> element. The mapped + column contains sequential integers that are numbered from zero by default. + + + + + + + + ]]> + + + + column (required): the name of the column holding the collection index values. + + + + + base (optional - defaults to 0): the value of the index column + that corresponds to the first element of the list or array. + + + + + + + + + + + + + ]]> + + + + column (required unless formula is used): the name of the column + holding the map key values. + + + + + formula (optional): a SQL formula used to evaluate the key of the map. + + + + + type (required): the type of the map keys. + + + + + length (optional): If the type takes a length and does not + already specify it, its length. + + + + + + + + + + + + + + ]]> + + + + column (required unless formula is used): the name of the column + holding the map key values. + + + + + formula (optional): a SQL formula used to evaluate the key of the map. + + + + + class (required): the entity class used as the map key. + + + + + entity-name (optional): the entity name of the associated class. + + + + + foreign-key (optional): specifies the name of the foreign key + constraint for DDL generation. + + + + + + + + + + + + + + + + ... +/>]]> + + + + class (required): the component class used as the map key. Make sure + you override GetHashCode() and Equals() + correctly on the component class. + + + + + <key-property>: maps a component property. + + + + + <key-many-to-one>: maps a component many-to-one association. + + + + + + + If your table does not have an index column, and you still wish to use IList as the + property type, you can map the property as a NHibernate <bag>. A bag does not + retain its order when it is retrieved from the database, but it can be optionally sorted or ordered. + Also consider using an ISet as the property type. + + + + The <index>, <index-many-to-many> and + <composite-index> elements are obsoleted predecessors to + <map-key>/<list-index>, + <map-key-many-to-many> and <composite-map-key> respectively. + + + + + + Collections of Values and Many-To-Many Associations + + + Any collection of values or many-to-many associations requires a dedicated + collection table with a foreign + key column or columns, collection element column or columns, and + possibly an index column or columns. + + + + For a collection of values, use the <element> tag. + + + + + + + + + + + + + + ]]> + + + + column (required unless formula is used): the + name of the column holding the collection element values. + + + + + formula (optional): an SQL formula used to evaluate the element. + + + + + type (required): the type of the collection element. + + + + + length (optional): if the type takes a length and does not + already specify it, its length. + + + + + precision (optional): if the type takes a precision and does not + already specify it, its precision. + + + + + scale (optional): if the type takes a scale and does not + already specify it, its scale. + + + + + not-null (optional - defaults to false): + sets the column nullability for DDL generation. + + + + + unique (optional - defaults to false): + sets the column uniqueness for DDL generation. + + + + + + + A many-to-many association is specified using the + <many-to-many> element. + + + + + + + + + + + + + + + + + + + ]]> + + + + column (required unless formula is used): the + name of the element foreign key column. + + + + + formula (optional): an SQL formula used to evaluate the element + foreign key value. + + + + + class (required): the name of the associated class. + + + + + fetch (optional, defaults to join): + enables outer-join or sequential select fetching for this association. This is a + special case; for full eager fetching (in a single SELECT) of an entity and its + many-to-many relationships to other entities, you would enable join fetching not + only of the collection itself, but also with this attribute on the + <many-to-many> nested element. + + + + + lazy (optional, defaults to proxy): + may be used to disable lazy fetching and specify that the associated entities + are always eagerly fetched. This is a special case; disabling laziness of the + collection itself only would only eagerly load the list of ids of the associated + entities. For fully loading the associated entities instead, while keeping + fetch value as select, you would also + disable laziness with this attribute on the <many-to-many> + nested element. + + + + + not-found (optional - defaults to exception): + specifies how foreign keys that reference missing rows will be handled. + ignore will treat a missing row as a null association. + + + + + entity-name (optional): the entity name of the associated class. + + + + + property-ref (optional): the name of a property of the associated + class that is joined to this foreign key. If not specified, the primary key of the + associated class is used. + + + + + order-by (optional): specifies a table column (or columns) that + defines the iteration order of the collection. This is a special case; the + order-by on the collection could order only by the foreign key. + The order-by on the <many-to-many> + nested element allows to order by the associated entity columns. + + + + + where (optional): specifies an arbitrary SQL WHERE + condition to be used when retrieving or removing the collection. This is a special case; the + where on the collection could filter only by the foreign key. + The where on the <many-to-many> + nested element allows to filter by the associated entity columns. + + + + + unique (optional): enables the DDL generation of a unique constraint + for the foreign-key column. This makes the association multiplicity effectively + one-to-many. + + + + + foreign-key (optional): specifies the name of the foreign key + constraint for DDL generation. + + + + + outer-join (optional): This attribute is obsoleted in favor of + fetch. auto is equivalent to not specifying + fetch, true is equivalent to + join and false is equivalent to + select. + + + + - - Collections of Values and Many-To-Many Associations + + Here are some examples. + - - A collection table is required for any collection of values and any collection of - references to other entities mapped as a many-to-many association (the natural semantics - for a .NET collection). The table requires (foreign) key column(s), element column(s) and - possibly index column(s). - + + A set of strings: + - - The foreign key from the collection table to the table of the owning class is - declared using a <key> element. - + + + +]]> - - - - - ]]> - - - - column (required): The name of the foreign key column. - - - - + + A bag containing integers with an iteration order determined by the + order-by attribute: + - - For indexed collections like maps and lists, we require an <index> - element. For lists, this column contains sequential integers numbered from zero. Make sure - that your index really starts from zero if you have to deal with legacy data. For maps, - the column may contain any values of any NHibernate type. - + + + +]]> - - - - - - ]]> - - - - column (required): The name of the column holding the - collection index values. - - - - - type (optional, defaults to Int32): - The type of the collection index. - - - - + + An array of entities, in this case, a many-to-many association (note that + the entities are lifecycle objects, cascade="all", see + ): + - - Alternatively, a map may be indexed by objects of entity type. We use the - <index-many-to-many> element. - + + + + +]]> - - - - - - ]]> - - - - column (required): The name of the foreign key - column for the collection index values. - - - - - class (required): The entity class used as the - collection index. - - - - + + A map from string indices to dates: + - - For a collection of values, we use the <element> tag. - + + + + +]]> - - - - - - ]]> - - - - column (required): The name of the column holding the - collection element values. - - - - - type (required): The type of the collection element. - - - - + + A list of components (discussed in ): + - - A collection of entities with its own table corresponds to the relational notion - of many-to-many association. A many to many association is the - most natural mapping of a .NET collection but is not usually the best relational model. - + + + + + + + + +]]> - - - - - - - - ]]> - - - - column (required): The name of the element foreign key column. - - - + + + + One-To-Many Associations + + + A one-to-many association links the tables of two classes via a + foreign key with no intervening collection table. This mapping loses certain semantics + of normal .NET collections: + + + + - class (required): The name of the associated class. + No null values may be contained in a dictionary, set or list (unless + using not-found value ignore). - - + + - fetch (optional, defaults to join): - enables outer-join or sequential select fetching for this association. This is a - special case; for full eager fetching (in a single SELECT) of an entity and its - many-to-many relationships to other entities, you would enable join fetching not - only of the collection itself, but also with this attribute on the - <many-to-many> nested element. + An instance of the contained entity class cannot belong to more than + one instance of the collection. - - + + - not-found (optional - defaults to exception): - Specifies how foreign keys that reference missing rows will be handled: - ignore will treat a missing row as a null association. + An instance of the contained entity class cannot appear at more than + one value of the collection index. - - - + + + + + An association from Product to Part requires the + existence of a foreign key column and possibly an index column into the Part table. A + <one-to-many> tag indicates that this is a one-to-many + association. + + + + + + + + + ]]> + + + + class (required): the name of the associated class. + + + + + not-found (optional - defaults to exception): + specifies how foreign keys that reference missing rows will be handled. + ignore will treat a missing row as a null association. + + + + + entity-name (optional): the entity name of the associated class. + + + + + + + The <one-to-many> element does not need to declare any columns. Nor is + it necessary to specify the table name anywhere. + + + + Very Important Note: If the foreign key column of an + <one-to-many> association is declared NOT NULL, you + must declare the <key> mapping not-null="true" or + use a bidirectional association with the collection mapping marked + inverse="true". See for more + information. + + + + Example: + + + + + +]]> - - Some examples, first, a set of strings: - + - - - -]]> + - - A bag containing integers (with an iteration order determined by the - order-by attribute): - + + Advanced collection mappings - - - -]]> + + Sorted Collections - - An array of entities - in this case, a many to many association (note that - the entities are lifecycle objects, cascade="all"): - + + NHibernate supports collections implemented by System.Collections.Generic.SortedList<T> and + System.Collections.Generic.SortedSet<T>. You must specify a comparer in the mapping file: + - - - - -]]> + + + + - - A map from string indices to dates: - + + + + +]]> + + + Allowed values of the sort attribute are unsorted, + natural and the name of a class implementing + System.Collections.Generic.IComparer<T>. + + + + If you want the database itself to order the collection elements use the + order-by attribute of set, bag + or map mappings. This performs the ordering in the SQL query, not in + memory. + + + + Setting the order-by attribute tells NHibernate to use + Iesi.Collections.Generic.LinkedHashSet class + internally for sets, maintaining the order of the elements. It is not supported on maps, + unless specifying also a custom collection-type implementing + IUserCollectionType. + + + + + + + + + + + +]]> + + + Note that the value of the order-by attribute is an SQL ordering, not + a HQL ordering! + + + + Associations can even be sorted by some arbitrary criteria at runtime using a + CreateFilter(). + + + ();]]> + + + + + Bidirectional Associations + + + A bidirectional association allows navigation from both + "ends" of the association. Two kinds of bidirectional association are + supported: + + + + one-to-many + + + set or bag valued at one end, single-valued at the other + + + + + many-to-many + + + set or bag valued at both ends + + + + + + + + + You can specify a bidirectional many-to-many association simply by mapping two + many-to-many associations to the same database table and declaring one end as + inverse. You cannot select an indexed collection. + + + + Here is an example of a bidirectional many-to-many association that illustrates how each + category can have many items and each item can be in many categories: + + + + + ... + + + + + + + + + ... + + + + + + +]]> + + + Changes made only to the inverse end of the association are not + persisted. This means that NHibernate has two representations in memory for every + bidirectional association, one link from A to B and another link from B to A. This + is easier to understand if you think about the .NET object model and how we create + a many-to-many relationship in C#: + + + + + + The non-inverse side is used to save the in-memory representation to the database. + We would get an unnecessary INSERT/UPDATE and probably even a foreign key violation + if both would trigger changes! The same is of course also true for bidirectional + one-to-many associations. + + + + You can map a bidirectional one-to-many association by mapping a one-to-many association + to the same table column(s) as a many-to-one association and declaring the many-valued + end inverse="true". + + + + + ... + + + + + + + + + ... + +]]> + + + Mapping one end of an association with inverse="true" doesn't + affect the operation of cascades as these are orthogonal concepts. + + + + + + Bidirectional associations with indexed collections + + + A bidirectional association where one end is represented as a <list> + or <map>, requires special consideration. If there is a property of + the child class that maps to the index column you can use inverse="true" + on the collection mapping: + + + + + ... + + + + + + + + + + ... + + +]]> + + + If there is no such property on the child class, the association cannot be considered truly + bidirectional. That is, there is information available at one end of the association that is not + available at the other end. In this case, you cannot map the collection + inverse="true". Instead, you could use the following mapping: + + + + + ... + + + + + + + + + + ... + +]]> - - - - -]]> + + Note that in this mapping, the collection-valued end of the association is responsible for + updates to the foreign key. + - - A list of components (discussed in the next chapter): - + - - - - - - - - -]]> + + Ternary Associations - + + There are three possible approaches to mapping a ternary association. One approach is to use + an IDictionary with an association as its index: + - - One-To-Many Associations + + + + +]]> - - A one to many association links the tables of two classes - directly, with no intervening collection table. - (This implements a one-to-many relational model.) This - relational model loses some of the semantics of .NET collections: - + + + + +]]> - - - - No null values may be contained in a dictionary, set or list - - - - - An instance of the contained entity class may not belong to more than - one instance of the collection - - - - - An instance of the contained entity class may not appear at more than - one value of the collection index - - - + + A second approach is to remodel the association as an entity class. This is the most common + approach. + + + + A final alternative is to use composite elements, see . + + + + + + Using an <literal><idbag></literal> + + + If you've fully embraced our view that composite keys are a bad thing and that + entities should have synthetic identifiers (surrogate keys), then you might + find it a bit odd that the many to many associations and collections of values + that we've shown so far all map to tables with composite keys! Now, this point + is quite arguable; a pure association table doesn't seem to benefit much from + a surrogate key (though a collection of composite values might). + Nevertheless, NHibernate provides a feature that allows you to map many-to-many + associations and collections of values to a table with a surrogate key. + + + + The <idbag> element lets you map a List + (or Collection) with bag semantics. + + + + + + + + +]]> - - An association from Foo to Bar requires the - addition of a key column and possibly an index column to the table of the contained - entity class, Bar. These columns are mapped using the - <key> and <index> elements - described above. - + + An <idbag> has a synthetic id generator, + just like an entity class. A different surrogate key is assigned to each collection + row. NHibernate does not, however, provide any mechanism to discover the surrogate key value + of a particular row. + - - The <one-to-many> tag indicates a one to many association. - + + The update performance of an <idbag> supersedes a regular + <bag>. NHibernate can locate individual rows efficiently and update + or delete them individually, similar to a <list>, + <map> or <set>. + - - - - - - ]]> - - - - class (required): The name of the associated class. - - - - - not-found (optional - defaults to exception): - Specifies how foreign keys that reference missing rows will be handled: - ignore will treat a missing row as a null association. - - - - + + As of version 2.0, the native identifier generation + strategy is supported for <idbag> collection identifiers. + - - Example: - + - - - -]]> + + Heterogeneous Associations - - Notice that the <one-to-many> element does not need to - declare any columns. Nor is it necessary to specify the table - name anywhere. - + + The <many-to-any> and <index-many-to-any> + elements provide for true heterogeneous associations. These mapping elements work in the + same way as the <any> + element - and should also be used rarely, if ever. + - - Very Important Note: If the <key> - column of a <one-to-many> association is declared - NOT NULL, NHibernate may cause constraint violations - when it creates or updates the association. To prevent this problem, - you must use a bidirectional association with the many valued - end (the set or bag) marked as inverse="true". - See the discussion of bidirectional associations later in this chapter. - + @@ -627,8 +1324,7 @@ int accessLevel = permissions["accounts"]; // Error!]]> - Alternatively, use a non-lazy collection. Since lazy initialization can lead to - bugs like that above, non-laziness is the default. However, it is intended that + Alternatively, use a non-lazy collection. However, it is intended that lazy initialization be used for almost all collections, especially for collections of entities (for reasons of efficiency). @@ -639,10 +1335,11 @@ int accessLevel = permissions["accounts"]; // Error!]]> - Declare a lazy collection using the optional lazy attribute: + Disable lazy initialization of collection by using the optional lazy + attribute: - + ]]> @@ -710,337 +1407,15 @@ int accessLevel = permissions["accounts"]; // Error!]]> - - Sorted Collections - - - NHibernate supports collections implemented by System.Collections.Generic.SortedList<T> and - System.Collections.Generic.SortedSet<T>. You must specify a comparer in the mapping file: - - - - - - - - - - - -]]> - - - Allowed values of the sort attribute are unsorted, - natural and the name of a class implementing - System.Collections.Generic.IComparer<T>. - - - - If you want the database itself to order the collection elements use the - order-by attribute of set, bag - or map mappings. This performs the ordering in the SQL query, not in - memory. - - - - Setting the order-by attribute tells NHibernate to use - Iesi.Collections.Generic.LinkedHashSet class - internally for sets, maintaining the order of the elements. It is not supported on maps. - - - - - - - - - - - -]]> - - - Note that the value of the order-by attribute is an SQL ordering, not - a HQL ordering! - - - - Associations may even be sorted by some arbitrary criteria at runtime using a - CreateFilter(). - - - ();]]> - - - - - Using an <literal><idbag></literal> - - - If you've fully embraced our view that composite keys are a bad thing and that - entities should have synthetic identifiers (surrogate keys), then you might - find it a bit odd that the many to many associations and collections of values - that we've shown so far all map to tables with composite keys! Now, this point - is quite arguable; a pure association table doesn't seem to benefit much from - a surrogate key (though a collection of composite values might). - Nevertheless, NHibernate provides a feature that allows you to map many to many - associations and collections of values to a table with a surrogate key. - - - - The <idbag> element lets you map a List - (or Collection) with bag semantics. - - - - - - - - -]]> - - - As you can see, an <idbag> has a synthetic id generator, - just like an entity class! A different surrogate key is assigned to each collection - row. NHibernate does not provide any mechanism to discover the surrogate key value - of a particular row, however. - - - - Note that the update performance of an <idbag> is - much better than a regular <bag>! - NHibernate can locate individual rows efficiently and update or delete them - individually, just like a list, map or set. - - - - As of version 2.0, the native identifier generation - strategy is supported for <idbag> collection identifiers. - - - - - - Bidirectional Associations - - - A bidirectional association allows navigation from both - "ends" of the association. Two kinds of bidirectional association are - supported: - - - - one-to-many - - - set or bag valued at one end, single-valued at the other - - - - - many-to-many - - - set or bag valued at both ends - - - - - - - - - You may specify a bidirectional many-to-many association simply by mapping two - many-to-many associations to the same database table and declaring one end as - inverse (which one is your choice). Here's an example of - a bidirectional many-to-many association from a class back to itself - (each category can have many items and each item can be in many categories): - - - - - ... - - - - - - - - - ... - - - - - - -]]> - - - Changes made only to the inverse end of the association are not - persisted. This means that NHibernate has two representations in memory for every - bidirectional association, one link from A to B and another link from B to A. This - is easier to understand if you think about the .NET object model and how we create - a many-to-many relationship in C#: - - - - - - The non-inverse side is used to save the in-memory representation to the database. - We would get an unnecessary INSERT/UPDATE and probably even a foreign key violation - if both would trigger changes! The same is of course also true for bidirectional - one-to-many associations. - - - - You may map a bidirectional one-to-many association by mapping a one-to-many association - to the same table column(s) as a many-to-one association and declaring the many-valued - end inverse="true". - - - - - .... - - - - - - - - - .... - -]]> - - - Mapping one end of an association with inverse="true" doesn't - affect the operation of cascades, both are different concepts! - - - - - - Bidirectional associations with indexed collections - - - There are some additional considerations for bidirectional mappings with indexed collections - (where one end is represented as a <list> or <map>) - when using NHibernate mapping files. If there is a property of the child class that maps to the - index column you can use inverse="true" on the collection mapping: - - - - - .... - - - - - - - - - - .... - - -]]> - - - If there is no such property on the child class, the association cannot be considered truly - bidirectional. That is, there is information available at one end of the association that is not - available at the other end. In this case, you cannot map the collection - inverse="true". Instead, you could use the following mapping: - - - - - .... - - - - - - - - - - .... - -]]> - - - Note that in this mapping, the collection-valued end of the association is responsible for - updates to the foreign key. - - - - - - Ternary Associations + + Collection examples - There are two possible approaches to mapping a ternary association. One approach is to use - composite elements (discussed below). Another is to use an IDictionary with an - association as its index: + This section covers collection examples. - - - - -]]> - - - - - -]]> - - - - - Heterogeneous Associations - - - The <many-to-any> and <index-many-to-any> - elements provide for true heterogeneous associations. These mapping elements work in the - same way as the <any> element - and should also be used - rarely, if ever. - - - - - - Collection examples - - The previous sections are pretty confusing. So lets look at an example. This - class: + The following class has a collection of Child instances: Children { get; set; } + public virtual ISet Children { get; set; } - .... - .... + ... } }]]> - has a collection of Eg.Child instances. If each - child has at most one parent, the most natural mapping is a one-to-many + If each child has at most one parent, the most natural mapping is a one-to-many association: @@ -1072,7 +1445,7 @@ namespace Eg - + @@ -1095,6 +1468,10 @@ namespace Eg create table child (Id bigint not null primary key, Name varchar(255), parent_id bigint) alter table child add constraint childfk0 (parent_id) references parent]]> + + The Child class has no property referencing its parent. + + If the parent is required, use a bidirectional one-to-many association: @@ -1107,7 +1484,7 @@ alter table child add constraint childfk0 (parent_id) references parent]]> - + @@ -1118,7 +1495,7 @@ alter table child add constraint childfk0 (parent_id) references parent]]> - + ]]> @@ -1134,6 +1511,38 @@ create table child ( Id bigint not null parent_id bigint not null ) alter table child add constraint childfk0 (parent_id) references parent]]> + + Here, the Child class has a Parent property. + + + + Alternatively, if this association must be unidirectional you can declare the + NOT NULL constraint on the <key> + mapping: + + + + + + + + + + + + + + + + + + + + + +]]> + On the other hand, if a child might have multiple parents, a many-to-many association is appropriate: @@ -1146,7 +1555,7 @@ alter table child add constraint childfk0 (parent_id) references parent]]> - + @@ -1174,7 +1583,8 @@ alter table childset add constraint childsetfk0 (parent_id) references parent alter table childset add constraint childsetfk1 (child_id) references child]]> - See also . + For more examples and a complete explanation of a parent/child relationship mapping, + see and . diff --git a/doc/reference/modules/component_mapping.xml b/doc/reference/modules/component_mapping.xml index a1c6ece329e..33b4a21342a 100644 --- a/doc/reference/modules/component_mapping.xml +++ b/doc/reference/modules/component_mapping.xml @@ -10,21 +10,20 @@ Dependent objects - A component is a contained object that is persisted as a value type, not an entity. - The term "component" refers to the object-oriented notion of composition - (not to architecture-level components). For example, you might model a person like this: + A component is a contained object that is persisted as a value type and not an entity + reference. The term "component" refers to the object-oriented notion of composition and + not to architecture-level components. For example, you can model a person like this: Now Name may be persisted as a component of - Person. Notice that Name defines getter - and setter methods for its persistent properties, but doesn't need to declare + Person. Name defines getter + and setter methods for its persistent properties, but it does not need to declare any interfaces or identifier properties. @@ -68,16 +67,18 @@ - Like all value types, components do not support shared references. The null + Like value types, components do not support shared references. In other words, two + persons could have the same name, but the two person objects would contain two + independent name objects that were only "the same" by value. The null value semantics of a component are ad hoc. When reloading the containing object, NHibernate will assume that if all component columns are - null, then the entire component is null. This should be okay for most purposes. + null, then the entire component is null. This is suitable for most purposes. - The properties of a component may be of any NHibernate type (collections, many-to-one + The properties of a component can be of any NHibernate type (collections, many-to-one associations, other components, etc). Nested components should not - be considered an exotic usage. NHibernate is intended to support a very fine-grained + be considered an exotic usage. NHibernate is intended to support a fine-grained object model. @@ -112,7 +113,7 @@ <composite-element> tag. - + @@ -128,41 +129,38 @@ - Composite elements may contain components but not collections. If your - composite element itself contains - components, use the <nested-composite-element> - tag. This is a pretty exotic case - a collection of components which - themselves have components. By this stage you should be asking yourself - if a one-to-many association is more appropriate. Try remodelling the - composite element as an entity - but note that even though the object model - is the same, the relational model and persistence semantics are still - slightly different. + Composite elements can contain components but not collections. If your composite + element contains components, use the + <nested-composite-element> tag. This case is a collection + of components which themselves have components. You may want to consider if a + one-to-many association is more appropriate. Remodel the composite element as an + entity, but be aware that even though the .Net model is the same, the relational + model and persistence semantics are still slightly different. - Please note that a composite element mapping doesn't support null-able properties - if you're using a <set>. NHibernate - has to use each columns value to identify a record when deleting objects - (there is no separate primary key column in the composite element table), - which is not possible with null values. You have to either use only - not-null properties in a composite-element or choose a + A composite element mapping does not support null-able properties if you are using + a <set>. There is no separate primary key column in the + composite element table. NHibernate uses each column's value to identify a record + when deleting objects, which is not possible with null values. You have to either + use only not-null properties in a composite-element or choose a <list>, <map>, <bag> or <idbag>. A special case of a composite element is a composite element with a nested - <many-to-one> element. A mapping like this allows - you to map extra columns of a many-to-many association table to the - composite element class. The following is a many-to-many association - from Order to Item where + <many-to-one> element. This mapping allows you to map extra + columns of a many-to-many association table to the composite element class. The + following is a many-to-many association from + Order to Item where PurchaseDate, Price and Quantity are properties of the association: - - .... - + + ... + @@ -173,11 +171,18 @@ ]]> + + There cannot be a reference to the purchase on the other side for bidirectional association + navigation. Components are value types and do not allow shared references. A single + Purchase can be in the set of an Order, but it cannot + be referenced by the Item at the same time. + + Even ternary (or quaternary, etc) associations are possible: - - .... - + + ... + @@ -187,7 +192,7 @@ ]]> - Composite elements may appear in queries using the same syntax as + Composite elements can appear in queries using the same syntax as associations to other entities. @@ -197,10 +202,12 @@ Components as IDictionary indices - The <composite-index> element lets you map a + The <composite-map-key> element lets you map a component class as the key of an IDictionary. Make sure you override GetHashCode() and Equals() - correctly on the component class. + correctly on the component class. See + for more information on the <composite-map-key> + element. @@ -208,7 +215,7 @@ Components as composite identifiers - You may use a component as an identifier of an entity class. Your component + You can use a component as an identifier of an entity class. Your component class must satisfy certain requirements: @@ -234,91 +241,107 @@ - You can't use an IIdentifierGenerator to generate composite keys. + You cannot use an IIdentifierGenerator to generate composite keys. Instead the application must assign its own identifiers. Since a composite identifier must be assigned to the object before saving it, - we can't use unsaved-value of the identifier to distinguish + you cannot use unsaved-value of the identifier to distinguish between newly instantiated instances and instances saved in a previous session. + See for more information. - You may instead implement IInterceptor.IsTransient() if - you wish to use SaveOrUpdate() or cascading save / update. - As an alternative, you may also set the unsaved-value - attribute on a <version> (or - <timestamp>) element to specify a - value that indicates a new transient instance. In this case, the version - of the entity is used instead of the (assigned) identifier and you don't have - to implement IInterceptor.IsTransient() yourself. - - - - Use the <composite-id> tag (same attributes and - elements as <component>) in place of - <id> for the declaration of a composite identifier - class: + Use the <composite-id> tag, with nested + <key-property> or <key-many-to-one> + elements, in place of the usual <id> declaration. For example, + the following OrderLine class has a primary key that depends upon + the (composite) primary key of Order. - - - - - + + + + + + - .... + + + + + + ... ]]> - Now, any foreign keys into the table FOOS are also composite. - You must declare this in your mappings for other classes. An association to - Foo would be declared like this: + Any foreign keys referencing the OrderLine table are now composite. + Declare this in your mappings for other classes. An association to + OrderLine is mapped like this: - + - - - + + + ]]> - - This new <column> tag is also used by multi-column custom types. - Actually it is an alternative to the column attribute everywhere. A - collection with elements of type Foo would use: - + + The <column> element is an alternative to the column + attribute everywhere. Using the <column> element is required for + composite keys, but also gives more declaration options, which are mostly useful when using + hbm2ddl. See . + - - - - - - + + A many-to-many association to OrderLine also uses the composite foreign key: + + + + + + + + ]]> - On the other hand, <one-to-many>, as usual, declares no columns. + The collection of OrderLine in Order would use: + + + + + + + + +]]> + + + The <one-to-many> element declares no columns. - If Foo itself contains collections, they will also need a - composite foreign key. + If OrderLine itself owns a collection, it also has a composite foreign key. - - .... - .... - + + ... + - - - + + + - + + + ... + ]]> @@ -328,21 +351,23 @@ Dynamic components - You may even map a property of type IDictionary: + You can also map a property of type IDictionary or + IDictionary<string, object>: - + ]]> The semantics of a <dynamic-component> mapping are identical - to <component>. The advantage of this kind of mapping is + to <component>. The advantage of this kind of mapping is the ability to determine the actual properties of the component at deployment time, just - by editing the mapping document. (Runtime manipulation of the mapping document is - also possible, using a DOM parser.) + by editing the mapping document. Runtime manipulation of the mapping document is also + possible, using a DOM parser. You can also access, and change, NHibernate's + configuration-time metamodel via the Configuration object. diff --git a/doc/reference/modules/example_mappings.xml b/doc/reference/modules/example_mappings.xml index 0a09d2c6f4a..0355a3cd261 100644 --- a/doc/reference/modules/example_mappings.xml +++ b/doc/reference/modules/example_mappings.xml @@ -82,11 +82,11 @@ ]]> - - And here's the table schema generated by SchemaExport. - + + And here's the table schema generated by SchemaExport. + - ]]> - - There are four tables in this mapping. works, - authors and persons hold work, author - and person data respectively. author_work is an association - table linking authors to works. Here is the table schema, as generated by - SchemaExport. - + + There are four tables in this mapping. works, + authors and persons hold work, author + and person data respectively. author_work is an association + table linking authors to works. Here is the table schema, as generated by + SchemaExport. + - Customer/Order/Product - Now consider a model of the relationships between Customer, - Order and LineItem and Product. + In this section we consider a model of the relationships between Customer, + Order, LineItem and Product. There is a one-to-many association between Customer and - Order, but how should we represent Order / - LineItem / Product? I've chosen to map - LineItem as an association class representing the many-to-many + Order, but how can you represent Order / + LineItem / Product? In the example, + LineItem is mapped as an association class representing the many-to-many association between Order and Product. In NHibernate, this is called a composite element. @@ -299,7 +299,7 @@ alter table author_work - + @@ -316,14 +316,14 @@ alter table author_work ]]> - - customers, orders, line_items and - products hold customer, order, order line item and product data - respectively. line_items also acts as an association table linking - orders with products. - + + customers, orders, line_items and + products hold customer, order, order line item and product data + respectively. line_items also acts as an association table linking + orders with products. + - + + Miscellaneous example mappings + + + These examples have been elaborated from the Hibernate test suite. You will find many other + useful example mappings in NHibernate own test suite by searching in the test folder of the + NHibernate sources. + + + + "Typed" one-to-one association + + + + + Name + 'HOME' + + + Name + 'MAILING' + + + + + + + + + + + +]]> + + + + + Composite key example + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ( select sum(li.quantity * p.price) + from LineItem li, Product p + where li.productId = p.productId + and li.customerId = customerId + and li.orderNumber = orderNumber ) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ( select sum(li.quantity) + from LineItem li + where li.productId = productId ) + + +]]> + + + + + + + Content based discrimination + + + + + + + + + case + when Title is not null then 'E' + when Salesperson is not null then 'C' + else 'P' + end + + + + + + + + + + + + + + + + + + + + + + +]]> + + + + + Associations on alternate keys + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]]> + + + + + diff --git a/doc/reference/modules/example_parentchild.xml b/doc/reference/modules/example_parentchild.xml index 95304bf5f2a..ff53b25edd3 100644 --- a/doc/reference/modules/example_parentchild.xml +++ b/doc/reference/modules/example_parentchild.xml @@ -2,36 +2,35 @@ Example: Parent/Child - One of the very first things that new users try to do with NHibernate is to model a parent / child type - relationship. There are two different approaches to this. For various reasons the most convenient - approach, especially for new users, is to model both Parent and Child - as entity classes with a <one-to-many> association from Parent - to Child. (The alternative approach is to declare the Child as a - <composite-element>.) Now, it turns out that default semantics of a one to many - association (in NHibernate) are much less close to the usual semantics of a parent / child relationship than - those of a composite element mapping. We will explain how to use a bidirectional one to many - association with cascades to model a parent / child relationship efficiently and elegantly. It's - not at all difficult! + One of the first things that new users want to do with NHibernate is to model a parent/child type + relationship. There are two different approaches to this. The most convenient + approach, especially for new users, is to model both Parent and Child + as entity classes with a <one-to-many> association from Parent + to Child. The alternative approach is to declare the Child as a + <composite-element>. The default semantics of a one to many + association in NHibernate are much less close to the usual semantics of a parent/child relationship than + those of a composite element mapping. We will explain how to use a bidirectional one to many + association with cascades to model a parent/child relationship efficiently and elegantly. - + A note about collections - NHibernate collections are considered to be a logical part of their owning entity; never of the - contained entities. This is a crucial distinction! It has the following consequences: + NHibernate collections are considered to be a logical part of their owning entity and not of the + contained entities. Be aware that this is a critical distinction that has the following consequences: - When we remove / add an object from / to a collection, the version number of the collection owner + When you remove/add an object from/to a collection, the version number of the collection owner is incremented. - If an object that was removed from a collection is an instance of a value type (eg, a composite + If an object that was removed from a collection is an instance of a value type (e.g., a composite element), that object will cease to be persistent and its state will be completely removed from the database. Likewise, adding a value type instance to the collection will cause its state to be immediately persistent. @@ -39,9 +38,9 @@ - On the other hand, if an entity is removed from a collection (a one-to-many or many-to-many - association), it will not be deleted, by default. This behavior is completely consistent - a - change to the internal state of another entity should not cause the associated entity to vanish! + Conversely, if an entity is removed from a collection (a one-to-many or many-to-many + association), it will not be deleted by default. This behavior is completely consistent; a + change to the internal state of another entity should not cause the associated entity to vanish. Likewise, adding an entity to a collection does not cause that entity to become persistent, by default. @@ -49,12 +48,12 @@ - Instead, the default behavior is that adding an entity to a collection merely creates a link between - the two entities, while removing it removes the link. This is very appropriate for all sorts of cases. - Where it is not appropriate at all is the case of a parent / child relationship, where the life of the - child is bound to the lifecycle of the parent. + Adding an entity to a collection, by default, merely creates a link between the two entities. Removing + the entity will remove the link. This is appropriate for all sorts of cases. However, it is not + appropriate in the case of a parent/child relationship. In this case, the life of the child is bound to + the life cycle of the parent. - + @@ -69,54 +68,65 @@ ]]> - + - If we were to execute the following code + If we were to execute the following code: - - + NHibernate would issue two SQL statements: - - an INSERT to create the record for c - - - - an UPDATE to create the link from p to - c - - + + an INSERT to create the record for c + + + + an UPDATE to create the link from p to + c + + - + This is not only inefficient, but also violates any NOT NULL constraint on the - parent_id column. + parent_id column. You can fix the nullability constraint violation by specifying + not-null="true" in the collection mapping: + + + + + +]]> + + + However, this is not the recommended solution. - The underlying cause is that the link (the foreign key parent_id) from - p to c is not considered part of the state of the Child - object and is therefore not created in the INSERT. So the solution is to make the link part - of the Child mapping. + The underlying cause of this behavior is that the link (the foreign key + parent_id) from p to c is not considered + part of the state of the Child object and is therefore not created in the + INSERT. The solution is to make the link part of the Child + mapping. ]]> - (We also need to add the Parent property to the Child class.) + You also need to add the Parent property to the Child class. Now that the Child entity is managing the state of the link, we tell the collection not - to update the link. We use the inverse attribute. + to update the link. We use the inverse attribute to do this: @@ -125,7 +135,7 @@ session.Flush();]]> ]]> - The following code would be used to add a new Child. + The following code would be used to add a new Child: (pid); @@ -136,12 +146,11 @@ session.Save(c); session.Flush();]]> - And now, only one SQL INSERT would be issued! + Only one SQL INSERT would now be issued. - To tighten things up a bit, we could create an AddChild() method of - Parent. + You could also create an AddChild() method of Parent. }]]> - Now, the code to add a Child looks like + The code to add a Child looks like (pid); @@ -160,198 +169,202 @@ p.AddChild(c); session.Save(c); session.Flush();]]> - - - - Cascading lifecycle - - - The explicit call to Save() is still annoying. We will address this by - using cascades. - + + + + Cascading lifecycle + + + You can address the frustrations of the explicit call to Save() by using + cascades. + ]]> - - - This simplifies the code above to - + + + This simplifies the code above to: + (pid); Child c = new Child(); p.AddChild(c); session.Flush();]]> - - - Similarly, we don't need to iterate over the children when saving or deleting a Parent. - The following removes p and all its children from the database. - + + + Similarly, we do no more need to iterate over the children when saving or deleting a + Parent. The following removes p and all its children + from the database. + (pid); session.Delete(p); session.Flush();]]> - - - However, this code - + + + However, the following code: + (pid); // Get one child out of the set -IEnumerator childEnumerator = p.Children.GetEnumerator(); -childEnumerator.MoveNext(); -Child c = (Child) childEnumerator.Current; +Child c = p.Children.First(); p.Children.Remove(c); c.Parent = null; session.Flush();]]> - - - will not remove c from the database; it will only remove the link to p - (and cause a NOT NULL constraint violation, in this case). You need to explicitly - Delete() the Child. - + + + will not remove c from the database. In this case, it will only remove + the link to p and cause a NOT NULL constraint violation. + You need to explicitly Delete() the Child. + (pid); // Get one child out of the set -IEnumerator childEnumerator = p.Children.GetEnumerator(); -childEnumerator.MoveNext(); -Child c = (Child) childEnumerator.Current; +Child c = p.Children.First(); p.Children.Remove(c); session.Delete(c); session.Flush();]]> - - Now, in our case, a Child can't really exist without its parent. So if we remove - a Child from the collection, we really do want it to be deleted. For this, we must - use cascade="all-delete-orphan". - + + In our case, a Child cannot exist without its parent. So if we remove a + Child from the collection, we do want it to be deleted. To do this, we must + use cascade="all-delete-orphan". + ]]> - - Note: even though the collection mapping specifies inverse="true", cascades are still - processed by iterating the collection elements. So if you require that an object be saved, deleted or - updated by cascade, you must add it to the collection. It is not enough to simply set its parent. - - - - - - Using cascading <literal>Update()</literal> - - - Suppose we loaded up a Parent in one ISession, made some changes in a UI - action and wish to persist these changes in a new ISession (by calling Update()). The - Parent will contain a collection of children and, since cascading update is enabled, NHibernate - needs to know which children are newly instantiated and which represent existing rows in the database. Let's assume - that both Parent and Child have (synthetic) identifier properties of type - long. NHibernate will use the identifier property value to determine which of the - children are new. (You may also use the version or timestamp property, see - .) - - - - The unsaved-value attribute is used to specify the identifier value of a newly instantiated - instance. In NHibernate it is not necessary to specify unsaved-value explicitly. - - - - - The following code will update parent and child and insert - newChild. - - - + Even though the collection mapping specifies inverse="true", cascades are still + processed by iterating the collection elements. If you need an object be saved, deleted or + updated by cascade, you must add it to the collection. It is not enough to simply set its parent. + + + + + + Using cascading <literal>Update()</literal> + + + Suppose we loaded up a Parent in one ISession, made some + changes in a UI action and wanted to persist these changes in a new ISession + by calling Update(). The Parent will contain a collection + of children and, since the cascading update is enabled, NHibernate needs to know which children + are newly instantiated and which represent existing rows in the database. We will also assume + that both Parent and Child have generated identifier + properties of type long. NHibernate will use the identifier and + version/timestamp property value to determine which of the children are new. (See + .) + + + + The unsaved-value attribute is used to specify the identifier value of a newly + instantiated instance. In NHibernate it is not necessary to specify + unsaved-value explicitly. + + + + The following code will update parent and child and insert + newChild. + + + - - - Well, that is all very well for the case of a generated identifier, but what about assigned identifiers - and composite identifiers? This is more difficult, since unsaved-value can't - distinguish between a newly instantiated object (with an identifier assigned by the user) and an object - loaded in a previous session. In these cases, you will probably need to give NHibernate a hint; either - - - - - - define an unsaved-value on a <version> - or <timestamp> property mapping for the class. - - - - - set unsaved-value="none" and explicitly Save() - newly instantiated children before calling Update(parent) - - - - - set unsaved-value="any" and explicitly Update() - previously persistent children before calling Update(parent) - - - - - - null is the default unsaved-value for assigned identifiers, - none is the default unsaved-value for composite - identifiers. - - - - There is one further possibility. There is a new IInterceptor method named - IsTransient() which lets the application implement its own strategy for distinguishing - newly instantiated objects. For example, you could define a base class for your persistent classes. - - - + This may be suitable for the case of a generated identifier, but what about assigned identifiers + and composite identifiers? This is more difficult, since NHibernate cannot use the identifier + property to distinguish between a newly instantiated object, with an identifier assigned by the + user, and an object loaded in a previous session. In this case, NHibernate will either use the + timestamp or version property, or will actually query the second-level cache or, worst case, the + database, to see if the row exists. + + + + To avoid the worst case, either: + + + + + + define an unsaved-value on a <version> + or <timestamp> property mapping for the class. + + + + + set unsaved-value="none" and explicitly Save() + newly instantiated children before calling Update(parent). + + + + + set unsaved-value="any" and explicitly Update() + previously persistent children before calling Update(parent). + + + + + implement IInterceptor.IsTransient() for providing your own strategy + for distinguishing newly instantiated objects. + + + + + + For the IInterceptor solution, you could by example define a base class for + your persistent classes: + + + - - - (The saved property is non-persistent.) - Now implement IsTransient(), along with OnLoad(), - OnSave() and OnDelete() as follows. - - - + (The saved property is non-persistent.) + Then implement in you interceptor class IsTransient(), along with + OnLoad(), OnSave() and OnDelete() + as follows: + + + - - - - Conclusion - - - There is quite a bit to digest here and it might look confusing first time around. However, in practice, it - all works out quite nicely. Most NHibernate applications use the parent / child pattern in many places. - - - - We mentioned an alternative in the first paragraph. None of the above issues exist in the case of - <composite-element> mappings, which have exactly the semantics of a parent / child - relationship. Unfortunately, there are two big limitations to composite element classes: composite elements may - not own collections, and they should not be the child of any entity other than the unique parent. (However, - they may have a surrogate primary key, using an <idbag> mapping.) - - - - + + See for more information. + + + + + + Conclusion + + + There is quite a bit to digest here and it might look confusing first time around. However, in practice, it + all works out quite nicely. Most NHibernate applications use the parent / child pattern in many places. + + + + We mentioned an alternative in the first paragraph. None of the above issues exist in the case of + <composite-element> mappings, which have exactly the semantics of a parent/child + relationship. Unfortunately, there are two big limitations to composite element classes: composite elements + cannot own collections, and they should not be the child of any entity other than the unique parent. (However, + they may have a surrogate primary key, using an <idbag> mapping.) + + + + diff --git a/doc/reference/modules/filters.xml b/doc/reference/modules/filters.xml index 76fa8aa92f0..a6293203c69 100644 --- a/doc/reference/modules/filters.xml +++ b/doc/reference/modules/filters.xml @@ -71,11 +71,7 @@ A full example, using temporal data with an effective record date pattern: - - - - - + ... @@ -97,7 +93,11 @@ -]]> + + + + +]]> Then, in order to ensure that you always get back currently effective records, simply diff --git a/doc/reference/modules/inheritance_mapping.xml b/doc/reference/modules/inheritance_mapping.xml index 9c335cf7f56..d6e84613cee 100644 --- a/doc/reference/modules/inheritance_mapping.xml +++ b/doc/reference/modules/inheritance_mapping.xml @@ -5,81 +5,78 @@ The Three Strategies - NHibernate supports the three basic inheritance mapping strategies. + NHibernate supports the three basic inheritance mapping strategies: - - - table per class hierarchy - - - - - table per subclass - - - - - table per concrete class - - + + + table per class hierarchy + + + + + table per subclass + + + + + table per concrete class + + - + - In addition, NHibernate supports a fourth, slightly different kind of - polymorphism: + In addition, NHibernate supports a fourth, slightly different kind of polymorphism: - - - implicit polymorphism - - + + + implicit polymorphism + + - + - It is possible to use different mapping strategies for different - branches of the same inheritance hierarchy, and then make use of implicit - polymorphism to achieve polymorphism across the whole hierarchy. However, - NHibernate does not support mixing <subclass>, - and <joined-subclass> and + It is possible to use different mapping strategies for different branches of the same + inheritance hierarchy. You can then make use of implicit polymorphism to achieve polymorphism + across the whole hierarchy. However, NHibernate does not support mixing + <subclass>, and <joined-subclass> and <union-subclass> mappings under the same root - <class> element. It is possible to mix together - the table per hierarchy and table per subclass strategies, under the - the same <class> element, by combining the - <subclass> and <join> - elements (see below). + <class> element. It is possible to mix together the table per + hierarchy and table per subclass strategies, under the the same + <class> element, by combining the <subclass> + and <join> elements (see + ). - It is possible to define subclass, union-subclass, - and joined-subclass mappings in separate mapping documents, directly beneath - hibernate-mapping. This allows you to extend a class hierarchy just by adding - a new mapping file. You must specify an extends attribute in the subclass mapping, - naming a previously mapped superclass. - - - subclass, union-subclass, + and joined-subclass mappings in separate mapping documents directly beneath + hibernate-mapping. This allows you to extend a class hierarchy by adding + a new mapping file. You must specify an extends attribute in the subclass + mapping, naming a previously mapped superclass. + + + ]]> - - Table per class hierarchy + Table per class hierarchy - - Suppose we have an interface IPayment, with implementors - CreditCardPayment, CashPayment, - ChequePayment. The table-per-hierarchy mapping would - look like: - + + Suppose we have an interface IPayment, with implementors + CreditCardPayment, CashPayment, + ChequePayment. The table-per-hierarchy mapping would display in the + following way: + - + @@ -87,6 +84,7 @@ ... + ... @@ -97,22 +95,22 @@ ]]> - - Exactly one table is required. There is one big limitation of this - mapping strategy: columns declared by the subclasses may not have - NOT NULL constraints. - + + Exactly one table is required. There is a limitation of this mapping strategy: columns + declared by the subclasses, such as CCTYPE, cannot have + NOT NULL constraints. + Table per subclass - - A table-per-subclass mapping would look like: - + + A table-per-subclass mapping would look like: + - + @@ -120,6 +118,7 @@ ... + ... @@ -132,30 +131,27 @@ ]]> - - Four tables are required. The three subclass tables have primary - key associations to the superclass table (so the relational model - is actually a one-to-one association). - + + Four tables are required. The three subclass tables have primary key associations to the + superclass table so the relational model is actually a one-to-one association. + - Table per subclass, using a discriminator - - - Note that NHibernate's implementation of table-per-subclass requires - no discriminator column. Other object/relational mappers use a - different implementation of table-per-subclass which requires a type - discriminator column in the superclass table. The approach taken by - NHibernate is much more difficult to implement but arguably more - correct from a relational point of view. If you would like to use - a discriminator column with the table per subclass strategy, you - may combine the use of <subclass> and - <join>, as follow: - - - + Table per subclass, using a discriminator + + + NHibernate's implementation of table per subclass does not require a discriminator column. + Other object/relational mappers use a different implementation of table per subclass that + requires a type discriminator column in the superclass table. The approach taken by + NHibernate is much more difficult to implement, but arguably more correct from a relational + point of view. If you want to use a discriminator column with the table per subclass + strategy, you can combine the use of <subclass> and + <join>, as follows: + + + @@ -183,21 +179,21 @@ ]]> - - The optional fetch="select" declaration tells NHibernate - not to fetch the ChequePayment subclass data using an - outer join when querying the superclass. - + + The optional fetch="select" declaration tells NHibernate + not to fetch the ChequePayment subclass data using an + outer join when querying the superclass. + - Mixing table per class hierarchy with table per subclass + Mixing table per class hierarchy with table per subclass - - You may even mix the table per hierarchy and table per subclass strategies - using this approach: - + + You can even mix the table per hierarchy and table per subclass strategies + using the following approach: + @@ -220,25 +216,25 @@ ]]> - - For any of these mapping strategies, a polymorphic - association to IPayment is mapped using - <many-to-one>. - + + For any of these mapping strategies, a polymorphic + association to IPayment is mapped using + <many-to-one>. + + + ]]> - ]]> - - Table per concrete class + Table per concrete class - - There are two ways we could go about mapping the table per concrete class - strategy. The first is to use <union-subclass>. - + + There are two ways we can map the table per concrete class strategy. First, you can use + <union-subclass>. + - + @@ -256,41 +252,40 @@ ]]> - - Three tables are involved for the subclasses. Each table defines columns for - all properties of the class, including inherited properties. - - - - The limitation of this approach is that if a property is mapped on the - superclass, the column name must be the same on all subclass tables. - (We might relax this in a future release of NHibernate.) The identity - generator strategy is not allowed in union subclass inheritance, indeed - the primary key seed has to be shared across all unioned subclasses - of a hierarchy. - - - - If your superclass is abstract, map it with abstract="true". - Of course, if it is not abstract, an additional table (defaults to - PAYMENT in the example above) is needed to hold instances - of the superclass. - + + Three tables are involved for the subclasses. Each table defines columns for + all properties of the class, including inherited properties. + + + + The limitation of this approach is that if a property is mapped on the superclass, the + column name must be the same on all subclass tables. The identity generator strategy is + not allowed in union subclass inheritance. The primary key seed has to be shared across + all unioned subclasses of a hierarchy. + + + + If your superclass is abstract, map it with abstract="true". + If it is not abstract, an additional table (it defaults to + PAYMENT in the example above), is needed to hold instances + of the superclass. + - Table per concrete class, using implicit polymorphism + Table per concrete class, using implicit polymorphism - - An alternative approach is to make use of implicit polymorphism: - + + An alternative approach is to make use of implicit polymorphism: + - + + ... @@ -309,52 +304,49 @@ ... ]]> - - - Notice that nowhere do we mention the IPayment interface - explicitly. Also notice that properties of IPayment are - mapped in each of the subclasses. If you want to avoid duplication, consider - using XML entities - (e.g. [ <!ENTITY allproperties SYSTEM "allproperties.xml"> ] - in the DOCTYPE declaration and - &allproperties; in the mapping). - - - - The disadvantage of this approach is that NHibernate does not generate SQL - UNIONs when performing polymorphic queries. - - - For this mapping strategy, a polymorphic association to IPayment - is usually mapped using <any>. - + + Notice that the IPayment interface is not mentioned + explicitly. Also notice that properties of IPayment are + mapped in each of the subclasses. If you want to avoid duplication, consider + using XML entities (by example + [ <!ENTITY allproperties SYSTEM "allproperties.xml"> ] + in the DOCTYPE declaration and + &allproperties; in the mapping). + + + + The disadvantage of this approach is that NHibernate does not generate SQL + UNIONs when performing polymorphic queries. + - + + For this mapping strategy, a polymorphic association to IPayment + is usually mapped using <any>. + + + ]]> - + - Mixing implicit polymorphism with other inheritance mappings + Mixing implicit polymorphism with other inheritance mappings - - There is one further thing to notice about this mapping. - Since the subclasses are each mapped in their own - <class> element (and since - IPayment is just an interface), each of - the subclasses could easily be part of another table-per-class - or table-per-subclass inheritance hierarchy! (And you can - still use polymorphic queries against the - IPayment interface.) - - - + + Since the subclasses are each mapped in their own + <class> element and since + IPayment is just an interface, each of + the subclasses could easily be part of another inheritance hierarchy. You can + still use polymorphic queries against the IPayment interface. + + + @@ -382,28 +374,28 @@ ]]> - - Once again, we don't mention IPayment explicitly. If we - execute a query against the IPayment interface - for - example, from IPayment - NHibernate - automatically returns instances of CreditCardPayment - (and its subclasses, since they also implement IPayment), - CashPayment and ChequePayment but - not instances of NonelectronicTransaction. - + + Once again, IPayment is not mentioned explicitly. If we + execute a query against the IPayment interface - for + example, from IPayment - NHibernate + automatically returns instances of CreditCardPayment + (and its subclasses, since they also implement IPayment), + CashPayment and ChequePayment but + not instances of NonelectronicTransaction (provided it does + not implement IPayment). + - + Limitations - There are certain limitations to the "implicit polymorphism" approach to - the table per concrete-class mapping strategy. There are somewhat less - restrictive limitations to <union-subclass> - mappings. + There are limitations to the "implicit polymorphism" approach to the table per concrete-class + mapping strategy. There are somewhat less restrictive limitations to + <union-subclass> mappings. diff --git a/doc/reference/modules/manipulating_data.xml b/doc/reference/modules/manipulating_data.xml index e31b2e89de4..13fef4bee06 100644 --- a/doc/reference/modules/manipulating_data.xml +++ b/doc/reference/modules/manipulating_data.xml @@ -541,7 +541,8 @@ secondSession.Update(mate); // update mate]]> The application should individually Update() transient instances reachable from the given transient instance if and only if it wants - their state also updated. (Except for lifecycle objects, discussed later.) + their state also updated. (Except for lifecycle objects, see + .) @@ -591,8 +592,10 @@ secondSession.Update(mate); // update mate]]> - undefined - if set for version or - timestamp, then identifier check is used + undefined - do not infer the operation from the identifier + (or version, or timestamp). Ultimately, + NHibernate may query the database for determining the operation it has to + perform. @@ -680,9 +683,9 @@ secondSession.SaveOrUpdate(mate); // save the new instance (mate has a null id) if the object is versioned (version or - timestamp), then the version will take precedence - to identifier check, unless the versions - unsaved-value="undefined" (default value) + timestamp), and its version matches the criteria + specified by unsaved-value, Save() + it diff --git a/doc/reference/modules/performance.xml b/doc/reference/modules/performance.xml index 01a30cc1bff..bdaa4344044 100644 --- a/doc/reference/modules/performance.xml +++ b/doc/reference/modules/performance.xml @@ -539,7 +539,7 @@ using(var iter = session You may also enable batch fetching of collections. For example, if each Person has a lazy collection of Cats, and 10 persons are currently loaded in the - ISesssion, iterating through all persons will generate 10 SELECTs, + ISession, iterating through all persons will generate 10 SELECTs, one for every call to person.Cats. If you enable batch fetching for the Cats collection in the mapping of Person, NHibernate can pre-fetch collections: diff --git a/doc/reference/modules/persistent_classes.xml b/doc/reference/modules/persistent_classes.xml index 57d279be08e..ed81a02402a 100644 --- a/doc/reference/modules/persistent_classes.xml +++ b/doc/reference/modules/persistent_classes.xml @@ -115,7 +115,7 @@ namespace Eg - Cascaded updates (see "Lifecycle Objects") + Cascaded updates (see ) diff --git a/src/NHibernate/Async/Id/CounterGenerator.cs b/src/NHibernate/Async/Id/CounterGenerator.cs index 72d80bc3cc6..f9e4ee4e16c 100644 --- a/src/NHibernate/Async/Id/CounterGenerator.cs +++ b/src/NHibernate/Async/Id/CounterGenerator.cs @@ -35,4 +35,4 @@ public Task GenerateAsync(ISessionImplementor cache, object obj, Cancell } } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Async/Id/IdentifierGeneratorFactory.cs b/src/NHibernate/Async/Id/IdentifierGeneratorFactory.cs index 1d1acc07d6b..6df177e3780 100644 --- a/src/NHibernate/Async/Id/IdentifierGeneratorFactory.cs +++ b/src/NHibernate/Async/Id/IdentifierGeneratorFactory.cs @@ -65,9 +65,9 @@ public static async Task GetGeneratedIdentityAsync(DbDataReader rs, ITyp public static async Task GetAsync(DbDataReader rs, IType type, ISessionImplementor session, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); - // here is an interesting one: + // here is an interesting one: // - MsSql's @@identity returns a Decimal - // - MySql LAST_IDENITY() returns an Int64 + // - MySql LAST_IDENTITY() returns an Int64 try { return await (type.NullSafeGetAsync(rs, rs.GetName(0), session, null, cancellationToken)).ConfigureAwait(false); diff --git a/src/NHibernate/Async/Id/SequenceIdentityGenerator.cs b/src/NHibernate/Async/Id/SequenceIdentityGenerator.cs index b34e9372404..3204ecd576e 100644 --- a/src/NHibernate/Async/Id/SequenceIdentityGenerator.cs +++ b/src/NHibernate/Async/Id/SequenceIdentityGenerator.cs @@ -37,4 +37,4 @@ public override Task GenerateAsync(ISessionImplementor session, object o #endregion } -} \ No newline at end of file +} diff --git a/src/NHibernate/Async/Id/TableGenerator.cs b/src/NHibernate/Async/Id/TableGenerator.cs index 648806a5871..b2731653a92 100644 --- a/src/NHibernate/Async/Id/TableGenerator.cs +++ b/src/NHibernate/Async/Id/TableGenerator.cs @@ -65,7 +65,7 @@ public override async Task DoWorkInCurrentTransactionAsync(ISessionImple do { //the loop ensure atomicitiy of the - //select + uspdate even for no transaction + //select + update even for no transaction //or read committed isolation level (needed for .net?) var qps = conn.CreateCommand(); diff --git a/src/NHibernate/Id/CounterGenerator.cs b/src/NHibernate/Id/CounterGenerator.cs index 2ab35cebdaf..e199b00248c 100644 --- a/src/NHibernate/Id/CounterGenerator.cs +++ b/src/NHibernate/Id/CounterGenerator.cs @@ -6,7 +6,8 @@ namespace NHibernate.Id { /// /// An that returns a Int64 constructed from the system - /// time and a counter value. Not safe for use in a clustser! + /// time and a counter value. Not safe for use in a clustser! May generate colliding identifiers in + /// a bit less than one year. /// public partial class CounterGenerator : IIdentifierGenerator { @@ -28,7 +29,11 @@ protected short Count public object Generate(ISessionImplementor cache, object obj) { + // This causes the most significant digits to be shifted out, causing hi-part to cycle in a bit less than + // one year Count only serves to avoid collision for entities persisted in the same 100ns. Maybe it should + // have been (DateTime.Now.Ticks && 0xffff) instead, with count serving to avoid collision for up to 37767 + // entities in the same 6.5535ms. But changing this would be a breaking change for existing values. return unchecked ((DateTime.Now.Ticks << 16) + Count); } } -} \ No newline at end of file +} diff --git a/src/NHibernate/Id/IdentifierGeneratorFactory.cs b/src/NHibernate/Id/IdentifierGeneratorFactory.cs index c90ce69f956..97021d9baff 100644 --- a/src/NHibernate/Id/IdentifierGeneratorFactory.cs +++ b/src/NHibernate/Id/IdentifierGeneratorFactory.cs @@ -25,7 +25,7 @@ namespace NHibernate.Id /// /// /// - /// counter + /// counter (or vm) /// /// /// @@ -49,14 +49,18 @@ namespace NHibernate.Id /// /// /// + /// enhanced-table + /// + /// + /// /// identity /// /// /// /// native /// - /// Chooses between , - /// , and based on the + /// Chooses between , , + /// and based on the /// 's capabilities. /// /// @@ -73,6 +77,14 @@ namespace NHibernate.Id /// /// /// + /// sequence-identity + /// + /// + /// + /// trigger-identity + /// + /// + /// /// uuid.hex /// /// @@ -80,6 +92,10 @@ namespace NHibernate.Id /// uuid.string /// /// + /// + /// select + /// + /// /// /// public static partial class IdentifierGeneratorFactory @@ -122,9 +138,9 @@ public static object GetGeneratedIdentity(DbDataReader rs, IType type, ISessionI /// public static object Get(DbDataReader rs, IType type, ISessionImplementor session) { - // here is an interesting one: + // here is an interesting one: // - MsSql's @@identity returns a Decimal - // - MySql LAST_IDENITY() returns an Int64 + // - MySql LAST_IDENTITY() returns an Int64 try { return type.NullSafeGet(rs, rs.GetName(0), session, null); diff --git a/src/NHibernate/Id/IncrementGenerator.cs b/src/NHibernate/Id/IncrementGenerator.cs index 2b70c179998..1d4fef66ba7 100644 --- a/src/NHibernate/Id/IncrementGenerator.cs +++ b/src/NHibernate/Id/IncrementGenerator.cs @@ -22,7 +22,7 @@ namespace NHibernate.Id /// java author Gavin King, .NET port Mark Holden /// /// - /// Mapping parameters supported, but not usually needed: table, column. + /// Mapping parameters supported, but not usually needed: tables, column, schema, catalog. /// /// public partial class IncrementGenerator : IIdentifierGenerator, IConfigurable diff --git a/src/NHibernate/Id/SequenceIdentityGenerator.cs b/src/NHibernate/Id/SequenceIdentityGenerator.cs index 0cb572de5fb..af2b4f38660 100644 --- a/src/NHibernate/Id/SequenceIdentityGenerator.cs +++ b/src/NHibernate/Id/SequenceIdentityGenerator.cs @@ -5,7 +5,7 @@ namespace NHibernate.Id { /// /// A generator which combines sequence generation with immediate retrieval - /// by attaching a output parameter to the SQL command + /// by attaching an output parameter to the SQL command. /// In this respect it works much like ANSI-SQL IDENTITY generation. /// public partial class SequenceIdentityGenerator : SequenceGenerator, IPostInsertIdentifierGenerator @@ -52,4 +52,4 @@ public override IdentifierGeneratingInsert PrepareIdentifierGeneratingInsert() #endregion } -} \ No newline at end of file +} diff --git a/src/NHibernate/Id/TableGenerator.cs b/src/NHibernate/Id/TableGenerator.cs index 045ff128511..ce79bf2a532 100644 --- a/src/NHibernate/Id/TableGenerator.cs +++ b/src/NHibernate/Id/TableGenerator.cs @@ -218,7 +218,7 @@ public override object DoWorkInCurrentTransaction(ISessionImplementor session, D do { //the loop ensure atomicitiy of the - //select + uspdate even for no transaction + //select + update even for no transaction //or read committed isolation level (needed for .net?) var qps = conn.CreateCommand(); diff --git a/src/NHibernate/Id/TableHiLoGenerator.cs b/src/NHibernate/Id/TableHiLoGenerator.cs index 2ef2d2b6a85..402e5dbd467 100644 --- a/src/NHibernate/Id/TableHiLoGenerator.cs +++ b/src/NHibernate/Id/TableHiLoGenerator.cs @@ -22,12 +22,14 @@ namespace NHibernate.Id /// <param name="column">id_column</param> /// <param name="max_lo">max_lo_value</param> /// <param name="schema">db_schema</param> + /// <param name="catalog">db_catalog</param> + /// <param name="where">arbitrary additional where clause</param> /// </generator> /// ///

///

- /// The table and column parameters are required, the max_lo and - /// schema are optional. + /// The table and column parameters are required, the max_lo, + /// schema, catalog and where are optional. ///

///

/// The hi value MUST be fecthed in a separate transaction to the ISession diff --git a/src/NHibernate/Id/TriggerIdentityGenerator.cs b/src/NHibernate/Id/TriggerIdentityGenerator.cs index 3bb12786e57..f605ef4a3cf 100644 --- a/src/NHibernate/Id/TriggerIdentityGenerator.cs +++ b/src/NHibernate/Id/TriggerIdentityGenerator.cs @@ -3,6 +3,10 @@ namespace NHibernate.Id { + ///

+ /// A generator that uses an output parameter to return the identifier generated by the insert + /// on database server side. + /// public class TriggerIdentityGenerator : AbstractPostInsertGenerator { #region Overrides of AbstractPostInsertGenerator @@ -15,4 +19,4 @@ public override IInsertGeneratedIdentifierDelegate GetInsertGeneratedIdentifierD #endregion } -} \ No newline at end of file +}