Skip to content

Commit 3e59812

Browse files
committed
Merge branch 'NH-3383'
2 parents 09562e8 + eae467d commit 3e59812

File tree

3 files changed

+224
-3
lines changed

3 files changed

+224
-3
lines changed
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
using System;
2+
using System.IO;
3+
using System.Reflection;
4+
using System.Runtime.Serialization.Formatters.Binary;
5+
using NHibernate.Cfg.MappingSchema;
6+
using NHibernate.Engine;
7+
using NHibernate.Mapping;
8+
using NHibernate.Mapping.ByCode;
9+
using NHibernate.Type;
10+
using NUnit.Framework;
11+
12+
namespace NHibernate.Test.NHSpecificTest.NH3383
13+
{
14+
public class ByCodeFixture : TestCaseMappingByCode
15+
{
16+
protected override HbmMapping GetMappings()
17+
{
18+
var mapper = new ModelMapper();
19+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
20+
}
21+
22+
23+
[Test]
24+
public void DeserializedCascadeStyleRefersToSameObject()
25+
{
26+
CascadeStyle deserializedCascadeStyle;
27+
28+
using (var configMemoryStream = new MemoryStream())
29+
{
30+
var formatter = new BinaryFormatter();
31+
formatter.Serialize(configMemoryStream, CascadeStyle.Evict);
32+
configMemoryStream.Position = 0;
33+
deserializedCascadeStyle = (CascadeStyle) formatter.Deserialize(configMemoryStream);
34+
}
35+
36+
Assert.That(deserializedCascadeStyle, Is.SameAs(CascadeStyle.Evict));
37+
}
38+
39+
40+
[Test]
41+
public void CanRoundTripSerializedMultipleCascadeStyle()
42+
{
43+
CascadeStyle startingCascadeStyle =
44+
new CascadeStyle.MultipleCascadeStyle(new[] {CascadeStyle.Delete, CascadeStyle.Lock});
45+
CascadeStyle deserializedCascadeStyle;
46+
47+
using (var configMemoryStream = new MemoryStream())
48+
{
49+
var formatter = new BinaryFormatter();
50+
formatter.Serialize(configMemoryStream, startingCascadeStyle);
51+
configMemoryStream.Position = 0;
52+
deserializedCascadeStyle = (CascadeStyle)formatter.Deserialize(configMemoryStream);
53+
}
54+
55+
Assert.That(deserializedCascadeStyle, Is.TypeOf<CascadeStyle.MultipleCascadeStyle>());
56+
Assert.That(deserializedCascadeStyle.ToString(),
57+
Is.EqualTo(
58+
"[NHibernate.Engine.CascadeStyle+DeleteCascadeStyle,NHibernate.Engine.CascadeStyle+LockCascadeStyle]"));
59+
}
60+
61+
62+
[Test]
63+
public void DeserializedPropertyMapping_RefersToSameCascadeStyle()
64+
{
65+
var classMapping = CreateMappingClasses();
66+
67+
RootClass deserializedClassMapping;
68+
69+
using (MemoryStream configMemoryStream = new MemoryStream())
70+
{
71+
BinaryFormatter formatter = new BinaryFormatter();
72+
formatter.Serialize(configMemoryStream, classMapping);
73+
configMemoryStream.Position = 0;
74+
deserializedClassMapping = (RootClass)formatter.Deserialize(configMemoryStream);
75+
}
76+
77+
AssertDeserializedMappingClasses(deserializedClassMapping);
78+
}
79+
80+
// This test uses a seperate AppDomain to simulate the loading of a Configuration that was
81+
// serialized to the disk and is later deserialized in a new process.
82+
[Test]
83+
public void DeserializedPropertyMapping_CascadeStyleNotYetInitializedOnDeserialization_RefersToSameCascadeStyle()
84+
{
85+
var classMapping = CreateMappingClasses();
86+
87+
using (MemoryStream configMemoryStream = new MemoryStream())
88+
{
89+
BinaryFormatter formatter = new BinaryFormatter();
90+
formatter.Serialize(configMemoryStream, classMapping);
91+
configMemoryStream.Position = 0;
92+
93+
var secondAppDomain = AppDomain.CreateDomain(
94+
"SecondAppDomain",
95+
null,
96+
AppDomain.CurrentDomain.SetupInformation);
97+
98+
try
99+
{
100+
var helper = (AppDomainHelper)secondAppDomain.CreateInstanceAndUnwrap(
101+
Assembly.GetExecutingAssembly().FullName,
102+
typeof(AppDomainHelper).FullName);
103+
104+
helper.DeserializeAndAssert(configMemoryStream);
105+
}
106+
finally
107+
{
108+
AppDomain.Unload(secondAppDomain);
109+
}
110+
}
111+
}
112+
113+
private static RootClass CreateMappingClasses()
114+
{
115+
var classMapping = new RootClass();
116+
var componentMapping = new NHibernate.Mapping.Component(classMapping);
117+
118+
var componentPropertyMapping = new Property(componentMapping);
119+
componentPropertyMapping.Name = "ComponentPropertyInClass";
120+
classMapping.AddProperty(componentPropertyMapping);
121+
122+
var stringValue = new SimpleValue();
123+
stringValue.TypeName = typeof(string).FullName;
124+
125+
var stringPropertyInComponentMapping = new Property(stringValue);
126+
stringPropertyInComponentMapping.Name = "StringPropertyInComponent";
127+
componentMapping.AddProperty(stringPropertyInComponentMapping);
128+
129+
var componentType = (IAbstractComponentType)componentMapping.Type;
130+
131+
Assume.That(CascadeStyle.None == stringPropertyInComponentMapping.CascadeStyle);
132+
Assume.That(CascadeStyle.None == componentType.GetCascadeStyle(0));
133+
Assume.That(CascadeStyle.None == componentPropertyMapping.CascadeStyle);
134+
135+
return classMapping;
136+
}
137+
138+
private static void AssertDeserializedMappingClasses(RootClass deserializedClassMapping)
139+
{
140+
var deserializedComponentPropertyMapping = deserializedClassMapping.GetProperty("ComponentPropertyInClass");
141+
var deserializedComponentMapping = (NHibernate.Mapping.Component)deserializedComponentPropertyMapping.Value;
142+
var deserializedComponentType = (IAbstractComponentType)deserializedComponentMapping.Type;
143+
var deserializedStringPropertyInComponentMapping = deserializedComponentMapping.GetProperty("StringPropertyInComponent");
144+
145+
// Must be all the same objects since CascadeStyles are singletons and are
146+
// compared with "==" and "!=" operators.
147+
Assert.AreSame(CascadeStyle.None, deserializedStringPropertyInComponentMapping.CascadeStyle);
148+
Assert.AreSame(CascadeStyle.None, deserializedComponentType.GetCascadeStyle(0));
149+
Assert.AreSame(CascadeStyle.None, deserializedComponentPropertyMapping.CascadeStyle);
150+
}
151+
152+
private sealed class AppDomainHelper : MarshalByRefObject
153+
{
154+
public void DeserializeAndAssert(MemoryStream configMemoryStream)
155+
{
156+
BinaryFormatter formatter = new BinaryFormatter();
157+
var deserializedClassMapping = (RootClass)formatter.Deserialize(configMemoryStream);
158+
159+
AssertDeserializedMappingClasses(deserializedClassMapping);
160+
}
161+
}
162+
}
163+
}

src/NHibernate.Test/NHibernate.Test.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,7 @@
712712
<Compile Include="NHSpecificTest\NH3459\Order.cs" />
713713
<Compile Include="NHSpecificTest\NH2692\Fixture.cs" />
714714
<Compile Include="NHSpecificTest\NH2692\Model.cs" />
715+
<Compile Include="NHSpecificTest\NH3383\FixtureByCode.cs" />
715716
<Compile Include="NHSpecificTest\NH2772\Model.cs" />
716717
<Compile Include="NHSpecificTest\NH2772\Fixture.cs" />
717718
<Compile Include="NHSpecificTest\NH3058\DomainClass.cs" />

src/NHibernate/Engine/CascadeStyle.cs

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Runtime.Serialization;
4+
using System.Security;
35
using NHibernate.Util;
46

57
namespace NHibernate.Engine
68
{
79
/// <summary> A contract for defining the aspects of cascading various persistence actions. </summary>
810
/// <seealso cref="CascadingAction"/>
911
[Serializable]
10-
public abstract class CascadeStyle
12+
public abstract class CascadeStyle : ISerializable
1113
{
1214
/// <summary> package-protected constructor</summary>
1315
internal CascadeStyle() {}
@@ -26,6 +28,19 @@ static CascadeStyle()
2628
Styles["remove"] = Delete; // adds remove as a sort-of alias for delete...
2729
Styles["delete-orphan"] = DeleteOrphan;
2830
Styles["none"] = None;
31+
32+
AliasByStyle[All] = "all";
33+
AliasByStyle[AllDeleteOrphan] = "all-delete-orphan";
34+
AliasByStyle[Update] = "save-update";
35+
AliasByStyle[Persist] = "persist";
36+
AliasByStyle[Merge] = "merge";
37+
AliasByStyle[Lock] = "lock";
38+
AliasByStyle[Refresh] = "refresh";
39+
AliasByStyle[Replicate] = "replicate";
40+
AliasByStyle[Evict] = "evict";
41+
AliasByStyle[Delete] = "delete";
42+
AliasByStyle[DeleteOrphan] = "delete-orphan";
43+
AliasByStyle[None] = "none";
2944
}
3045

3146
#region The CascadeStyle contract
@@ -63,7 +78,8 @@ public virtual bool HasOrphanDelete
6378

6479
#region Static helper methods
6580

66-
internal static readonly Dictionary<string, CascadeStyle> Styles = new Dictionary<string, CascadeStyle>();
81+
private static readonly Dictionary<string, CascadeStyle> Styles = new Dictionary<string, CascadeStyle>();
82+
private static readonly Dictionary<CascadeStyle, string> AliasByStyle = new Dictionary<CascadeStyle, string>();
6783

6884
/// <summary> Factory method for obtaining named cascade styles </summary>
6985
/// <param name="cascade">The named cascade style name. </param>
@@ -77,10 +93,41 @@ public static CascadeStyle GetCascadeStyle(string cascade)
7793
return style;
7894
}
7995

96+
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
97+
{
98+
string alias = AliasByStyle[this];
99+
info.SetType(typeof (CascadeStyleSingletonReference));
100+
info.AddValue("cascadestyle", alias, typeof (string));
101+
}
102+
103+
[Serializable]
104+
private sealed class CascadeStyleSingletonReference : IObjectReference, ISerializable
105+
{
106+
private readonly string _cascadeStyle;
107+
108+
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
109+
{
110+
throw new NotImplementedException("This class should not be serialized directly.");
111+
}
112+
113+
private CascadeStyleSingletonReference(SerializationInfo info, StreamingContext context)
114+
{
115+
_cascadeStyle = (string) info.GetValue("cascadestyle", typeof (string));
116+
}
117+
118+
[SecurityCritical]
119+
Object IObjectReference.GetRealObject(StreamingContext context)
120+
{
121+
// Redirect to the singleton instance for the correct cascade style.
122+
return GetCascadeStyle(_cascadeStyle);
123+
}
124+
}
125+
80126
#endregion
81127

82128
#region The CascadeStyle implementations
83129

130+
84131
[Serializable]
85132
private class AllDeleteOrphanCascadeStyle : CascadeStyle
86133
{
@@ -204,14 +251,24 @@ public override bool DoCascade(CascadingAction action)
204251
}
205252

206253
[Serializable]
207-
public sealed class MultipleCascadeStyle : CascadeStyle
254+
public sealed class MultipleCascadeStyle : CascadeStyle, ISerializable
208255
{
209256
private readonly CascadeStyle[] styles;
210257
public MultipleCascadeStyle(CascadeStyle[] styles)
211258
{
212259
this.styles = styles;
213260
}
214261

262+
private MultipleCascadeStyle(SerializationInfo info, StreamingContext context)
263+
{
264+
styles = (CascadeStyle[])info.GetValue("styles", typeof(CascadeStyle[]));
265+
}
266+
267+
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
268+
{
269+
info.AddValue("styles", styles);
270+
}
271+
215272
public override bool DoCascade(CascadingAction action)
216273
{
217274
for (int i = 0; i < styles.Length; i++)

0 commit comments

Comments
 (0)