-
Notifications
You must be signed in to change notification settings - Fork 934
/
Copy pathForeignGenerator.cs
129 lines (114 loc) · 4.19 KB
/
ForeignGenerator.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
using System.Collections;
using System.Collections.Generic;
using NHibernate.Engine;
using NHibernate.Persister.Entity;
using NHibernate.Type;
namespace NHibernate.Id
{
/// <summary>
/// An <see cref="IIdentifierGenerator" /> that uses the value of
/// the id property of an associated object
/// </summary>
/// <remarks>
/// <para>
/// This id generation strategy is specified in the mapping file as
/// <code>
/// <generator class="foreign">
/// <param name="property">AssociatedObject</param>
/// </generator>
/// </code>
/// </para>
/// The mapping parameter <c>property</c> is required.
/// </remarks>
public partial class ForeignGenerator : IIdentifierGenerator, IConfigurable
{
private string propertyName;
private string entityName;
#region IIdentifierGenerator Members
/// <summary>
/// Generates an identifier from the value of a Property.
/// </summary>
/// <param name="sessionImplementor">The <see cref="ISessionImplementor"/> this id is being generated in.</param>
/// <param name="obj">The entity for which the id is being generated.</param>
/// <returns>
/// The identifier value from the associated object or
/// <see cref="IdentifierGeneratorFactory.ShortCircuitIndicator"/> if the <c>session</c>
/// already contains <c>obj</c>.
/// </returns>
public object Generate(ISessionImplementor sessionImplementor, object obj)
{
var persister = sessionImplementor.Factory.GetEntityPersister(entityName);
object associatedObject = persister.GetPropertyValue(obj, propertyName);
if (associatedObject == null)
{
throw new IdentifierGenerationException("attempted to assign id from null one-to-one property: " + propertyName);
}
var foreignValueSourceType = GetForeignValueSourceType(persister);
object id;
try
{
id = ForeignKeys.GetEntityIdentifierIfNotUnsaved(
foreignValueSourceType.GetAssociatedEntityName(),
associatedObject,
sessionImplementor);
}
catch (TransientObjectException)
{
if (sessionImplementor is ISession session)
{
id = session.Save(foreignValueSourceType.GetAssociatedEntityName(), associatedObject);
}
else if (sessionImplementor is IStatelessSession statelessSession)
{
id = statelessSession.Insert(foreignValueSourceType.GetAssociatedEntityName(), associatedObject);
}
else
{
throw new IdentifierGenerationException("sessionImplementor is neither Session nor StatelessSession");
}
}
if (Contains(sessionImplementor, obj))
{
//abort the save (the object is already saved by a circular cascade)
return IdentifierGeneratorFactory.ShortCircuitIndicator;
}
return id;
}
private EntityType GetForeignValueSourceType(IEntityPersister persister)
{
var propertyType = persister.GetPropertyType(propertyName);
if (propertyType.IsEntityType)
{
return (EntityType) propertyType;
}
// try identifier mapper
return (EntityType) persister.GetPropertyType("_identifierMapper." + propertyName);
}
private static bool Contains(ISessionImplementor sessionImplementor, object obj)
{
return sessionImplementor is ISession session && session.Contains(obj);
}
#endregion
#region IConfigurable Members
/// <summary>
/// Configures the ForeignGenerator by reading the value of <c>property</c>
/// from the <c>parms</c> parameter.
/// </summary>
/// <param name="type">The <see cref="IType"/> the identifier should be.</param>
/// <param name="parms">An <see cref="IDictionary"/> of Param values that are keyed by parameter name.</param>
/// <param name="dialect">The <see cref="Dialect.Dialect"/> to help with Configuration.</param>
/// <exception cref="MappingException">
/// Thrown if the key <c>property</c> is not found in the <c>parms</c> parameter.
/// </exception>
public void Configure(IType type, IDictionary<string, string> parms, Dialect.Dialect dialect)
{
parms.TryGetValue(IdGeneratorParmsNames.EntityName, out entityName);
parms.TryGetValue("property", out propertyName);
if (propertyName == null || propertyName.Length == 0)
{
throw new MappingException("param named \"property\" is required for foreign id generation strategy");
}
}
#endregion
}
}