Skip to content

Commit 87893ab

Browse files
committed
Fix possible InvalidCastException in ActionQueue
1 parent 0b66742 commit 87893ab

File tree

6 files changed

+65
-51
lines changed

6 files changed

+65
-51
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System;
2+
using NHibernate.Engine;
3+
using NHibernate.Persister.Entity;
4+
5+
namespace NHibernate.Action
6+
{
7+
[Serializable]
8+
public abstract class AbstractEntityInsertAction : EntityAction
9+
{
10+
protected internal AbstractEntityInsertAction(
11+
object id,
12+
object[] state,
13+
object instance,
14+
IEntityPersister persister,
15+
ISessionImplementor session)
16+
: base(session, id, instance, persister)
17+
{
18+
State = state;
19+
}
20+
21+
public object[] State { get; }
22+
}
23+
}

src/NHibernate/Action/EntityIdentityInsertAction.cs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,17 @@
77
namespace NHibernate.Action
88
{
99
[Serializable]
10-
public sealed partial class EntityIdentityInsertAction : EntityAction
10+
public sealed partial class EntityIdentityInsertAction : AbstractEntityInsertAction
1111
{
1212
private readonly object lockObject = new object();
13-
private readonly object[] state;
1413
private readonly bool isDelayed;
1514
private readonly EntityKey delayedEntityKey;
1615
//private CacheEntry cacheEntry;
1716
private object generatedId;
1817

1918
public EntityIdentityInsertAction(object[] state, object instance, IEntityPersister persister, ISessionImplementor session, bool isDelayed)
20-
: base(session, null, instance, persister)
19+
: base(null, state, instance, persister, session)
2120
{
22-
this.state = state;
2321
this.isDelayed = isDelayed;
2422
delayedEntityKey = this.isDelayed ? GenerateDelayedEntityKey() : null;
2523
}
@@ -72,10 +70,10 @@ public override void Execute()
7270

7371
if (!veto)
7472
{
75-
generatedId = persister.Insert(state, instance, Session);
73+
generatedId = persister.Insert(State, instance, Session);
7674
if (persister.HasInsertGeneratedProperties)
7775
{
78-
persister.ProcessInsertGeneratedProperties(generatedId, instance, state, Session);
76+
persister.ProcessInsertGeneratedProperties(generatedId, instance, State, Session);
7977
}
8078
//need to do that here rather than in the save event listener to let
8179
//the post insert events to have a id-filled entity when IDENTITY is used (EJB3)
@@ -107,7 +105,7 @@ private void PostInsert()
107105
IPostInsertEventListener[] postListeners = Session.Listeners.PostInsertEventListeners;
108106
if (postListeners.Length > 0)
109107
{
110-
PostInsertEvent postEvent = new PostInsertEvent(Instance, generatedId, state, Persister, (IEventSource)Session);
108+
PostInsertEvent postEvent = new PostInsertEvent(Instance, generatedId, State, Persister, (IEventSource)Session);
111109
foreach (IPostInsertEventListener listener in postListeners)
112110
{
113111
listener.OnPostInsert(postEvent);
@@ -120,7 +118,7 @@ private void PostCommitInsert()
120118
IPostInsertEventListener[] postListeners = Session.Listeners.PostCommitInsertEventListeners;
121119
if (postListeners.Length > 0)
122120
{
123-
var postEvent = new PostInsertEvent(Instance, generatedId, state, Persister, (IEventSource) Session);
121+
var postEvent = new PostInsertEvent(Instance, generatedId, State, Persister, (IEventSource) Session);
124122
foreach (IPostInsertEventListener listener in postListeners)
125123
{
126124
listener.OnPostInsert(postEvent);
@@ -134,7 +132,7 @@ private bool PreInsert()
134132
bool veto = false;
135133
if (preListeners.Length > 0)
136134
{
137-
var preEvent = new PreInsertEvent(Instance, null, state, Persister, (IEventSource) Session);
135+
var preEvent = new PreInsertEvent(Instance, null, State, Persister, (IEventSource) Session);
138136
foreach (IPreInsertEventListener listener in preListeners)
139137
{
140138
veto |= listener.OnPreInsert(preEvent);

src/NHibernate/Action/EntityInsertAction.cs

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,17 @@
99
namespace NHibernate.Action
1010
{
1111
[Serializable]
12-
public sealed partial class EntityInsertAction : EntityAction
12+
public sealed partial class EntityInsertAction : AbstractEntityInsertAction
1313
{
14-
private readonly object[] state;
1514
private object version;
1615
private object cacheEntry;
1716

1817
public EntityInsertAction(object id, object[] state, object instance, object version, IEntityPersister persister, ISessionImplementor session)
19-
: base(session, id, instance, persister)
18+
: base(id, state, instance, persister, session)
2019
{
21-
this.state = state;
2220
this.version = version;
2321
}
2422

25-
public object[] State
26-
{
27-
get { return state; }
28-
}
29-
3023
protected internal override bool HasPostCommitEventListeners
3124
{
3225
get
@@ -56,7 +49,7 @@ public override void Execute()
5649
if (!veto)
5750
{
5851

59-
persister.Insert(id, state, instance, Session);
52+
persister.Insert(id, State, instance, Session);
6053

6154
EntityEntry entry = Session.PersistenceContext.GetEntry(instance);
6255
if (entry == null)
@@ -68,20 +61,20 @@ public override void Execute()
6861

6962
if (persister.HasInsertGeneratedProperties)
7063
{
71-
persister.ProcessInsertGeneratedProperties(id, instance, state, Session);
64+
persister.ProcessInsertGeneratedProperties(id, instance, State, Session);
7265
if (persister.IsVersionPropertyGenerated)
7366
{
74-
version = Versioning.GetVersion(state, persister);
67+
version = Versioning.GetVersion(State, persister);
7568
}
76-
entry.PostUpdate(instance, state, version);
69+
entry.PostUpdate(instance, State, version);
7770
}
7871
}
7972

8073
ISessionFactoryImplementor factory = Session.Factory;
8174

8275
if (IsCachePutEnabled(persister))
8376
{
84-
CacheEntry ce = new CacheEntry(state, persister, persister.HasUninitializedLazyProperties(instance), version, session, instance);
77+
CacheEntry ce = new CacheEntry(State, persister, persister.HasUninitializedLazyProperties(instance), version, session, instance);
8578
cacheEntry = persister.CacheEntryStructure.Structure(ce);
8679

8780
CacheKey ck = Session.GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName);
@@ -127,7 +120,7 @@ private void PostInsert()
127120
IPostInsertEventListener[] postListeners = Session.Listeners.PostInsertEventListeners;
128121
if (postListeners.Length > 0)
129122
{
130-
PostInsertEvent postEvent = new PostInsertEvent(Instance, Id, state, Persister, (IEventSource)Session);
123+
PostInsertEvent postEvent = new PostInsertEvent(Instance, Id, State, Persister, (IEventSource)Session);
131124
foreach (IPostInsertEventListener listener in postListeners)
132125
{
133126
listener.OnPostInsert(postEvent);
@@ -140,7 +133,7 @@ private void PostCommitInsert()
140133
IPostInsertEventListener[] postListeners = Session.Listeners.PostCommitInsertEventListeners;
141134
if (postListeners.Length > 0)
142135
{
143-
PostInsertEvent postEvent = new PostInsertEvent(Instance, Id, state, Persister, (IEventSource)Session);
136+
PostInsertEvent postEvent = new PostInsertEvent(Instance, Id, State, Persister, (IEventSource)Session);
144137
foreach (IPostInsertEventListener listener in postListeners)
145138
{
146139
listener.OnPostInsert(postEvent);
@@ -154,7 +147,7 @@ private bool PreInsert()
154147
bool veto = false;
155148
if (preListeners.Length > 0)
156149
{
157-
var preEvent = new PreInsertEvent(Instance, Id, state, Persister, (IEventSource) Session);
150+
var preEvent = new PreInsertEvent(Instance, Id, State, Persister, (IEventSource) Session);
158151
foreach (IPreInsertEventListener listener in preListeners)
159152
{
160153
veto |= listener.OnPreInsert(preEvent);

src/NHibernate/Async/Action/EntityIdentityInsertAction.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ namespace NHibernate.Action
1818
{
1919
using System.Threading.Tasks;
2020
using System.Threading;
21-
public sealed partial class EntityIdentityInsertAction : EntityAction
21+
public sealed partial class EntityIdentityInsertAction : AbstractEntityInsertAction
2222
{
2323

2424
public override async Task ExecuteAsync(CancellationToken cancellationToken)
@@ -41,10 +41,10 @@ public override async Task ExecuteAsync(CancellationToken cancellationToken)
4141

4242
if (!veto)
4343
{
44-
generatedId = await (persister.InsertAsync(state, instance, Session, cancellationToken)).ConfigureAwait(false);
44+
generatedId = await (persister.InsertAsync(State, instance, Session, cancellationToken)).ConfigureAwait(false);
4545
if (persister.HasInsertGeneratedProperties)
4646
{
47-
await (persister.ProcessInsertGeneratedPropertiesAsync(generatedId, instance, state, Session, cancellationToken)).ConfigureAwait(false);
47+
await (persister.ProcessInsertGeneratedPropertiesAsync(generatedId, instance, State, Session, cancellationToken)).ConfigureAwait(false);
4848
}
4949
//need to do that here rather than in the save event listener to let
5050
//the post insert events to have a id-filled entity when IDENTITY is used (EJB3)
@@ -77,7 +77,7 @@ private async Task PostInsertAsync(CancellationToken cancellationToken)
7777
IPostInsertEventListener[] postListeners = Session.Listeners.PostInsertEventListeners;
7878
if (postListeners.Length > 0)
7979
{
80-
PostInsertEvent postEvent = new PostInsertEvent(Instance, generatedId, state, Persister, (IEventSource)Session);
80+
PostInsertEvent postEvent = new PostInsertEvent(Instance, generatedId, State, Persister, (IEventSource)Session);
8181
foreach (IPostInsertEventListener listener in postListeners)
8282
{
8383
await (listener.OnPostInsertAsync(postEvent, cancellationToken)).ConfigureAwait(false);
@@ -91,7 +91,7 @@ private async Task PostCommitInsertAsync(CancellationToken cancellationToken)
9191
IPostInsertEventListener[] postListeners = Session.Listeners.PostCommitInsertEventListeners;
9292
if (postListeners.Length > 0)
9393
{
94-
var postEvent = new PostInsertEvent(Instance, generatedId, state, Persister, (IEventSource) Session);
94+
var postEvent = new PostInsertEvent(Instance, generatedId, State, Persister, (IEventSource) Session);
9595
foreach (IPostInsertEventListener listener in postListeners)
9696
{
9797
await (listener.OnPostInsertAsync(postEvent, cancellationToken)).ConfigureAwait(false);
@@ -106,7 +106,7 @@ private async Task<bool> PreInsertAsync(CancellationToken cancellationToken)
106106
bool veto = false;
107107
if (preListeners.Length > 0)
108108
{
109-
var preEvent = new PreInsertEvent(Instance, null, state, Persister, (IEventSource) Session);
109+
var preEvent = new PreInsertEvent(Instance, null, State, Persister, (IEventSource) Session);
110110
foreach (IPreInsertEventListener listener in preListeners)
111111
{
112112
veto |= await (listener.OnPreInsertAsync(preEvent, cancellationToken)).ConfigureAwait(false);

src/NHibernate/Async/Action/EntityInsertAction.cs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ namespace NHibernate.Action
2020
{
2121
using System.Threading.Tasks;
2222
using System.Threading;
23-
public sealed partial class EntityInsertAction : EntityAction
23+
public sealed partial class EntityInsertAction : AbstractEntityInsertAction
2424
{
2525

2626
public override async Task ExecuteAsync(CancellationToken cancellationToken)
@@ -45,7 +45,7 @@ public override async Task ExecuteAsync(CancellationToken cancellationToken)
4545
if (!veto)
4646
{
4747

48-
await (persister.InsertAsync(id, state, instance, Session, cancellationToken)).ConfigureAwait(false);
48+
await (persister.InsertAsync(id, State, instance, Session, cancellationToken)).ConfigureAwait(false);
4949

5050
EntityEntry entry = Session.PersistenceContext.GetEntry(instance);
5151
if (entry == null)
@@ -57,20 +57,20 @@ public override async Task ExecuteAsync(CancellationToken cancellationToken)
5757

5858
if (persister.HasInsertGeneratedProperties)
5959
{
60-
await (persister.ProcessInsertGeneratedPropertiesAsync(id, instance, state, Session, cancellationToken)).ConfigureAwait(false);
60+
await (persister.ProcessInsertGeneratedPropertiesAsync(id, instance, State, Session, cancellationToken)).ConfigureAwait(false);
6161
if (persister.IsVersionPropertyGenerated)
6262
{
63-
version = Versioning.GetVersion(state, persister);
63+
version = Versioning.GetVersion(State, persister);
6464
}
65-
entry.PostUpdate(instance, state, version);
65+
entry.PostUpdate(instance, State, version);
6666
}
6767
}
6868

6969
ISessionFactoryImplementor factory = Session.Factory;
7070

7171
if (IsCachePutEnabled(persister))
7272
{
73-
CacheEntry ce = new CacheEntry(state, persister, persister.HasUninitializedLazyProperties(instance), version, session, instance);
73+
CacheEntry ce = new CacheEntry(State, persister, persister.HasUninitializedLazyProperties(instance), version, session, instance);
7474
cacheEntry = persister.CacheEntryStructure.Structure(ce);
7575

7676
CacheKey ck = Session.GenerateCacheKey(id, persister.IdentifierType, persister.RootEntityName);
@@ -118,7 +118,7 @@ private async Task PostInsertAsync(CancellationToken cancellationToken)
118118
IPostInsertEventListener[] postListeners = Session.Listeners.PostInsertEventListeners;
119119
if (postListeners.Length > 0)
120120
{
121-
PostInsertEvent postEvent = new PostInsertEvent(Instance, Id, state, Persister, (IEventSource)Session);
121+
PostInsertEvent postEvent = new PostInsertEvent(Instance, Id, State, Persister, (IEventSource)Session);
122122
foreach (IPostInsertEventListener listener in postListeners)
123123
{
124124
await (listener.OnPostInsertAsync(postEvent, cancellationToken)).ConfigureAwait(false);
@@ -132,7 +132,7 @@ private async Task PostCommitInsertAsync(CancellationToken cancellationToken)
132132
IPostInsertEventListener[] postListeners = Session.Listeners.PostCommitInsertEventListeners;
133133
if (postListeners.Length > 0)
134134
{
135-
PostInsertEvent postEvent = new PostInsertEvent(Instance, Id, state, Persister, (IEventSource)Session);
135+
PostInsertEvent postEvent = new PostInsertEvent(Instance, Id, State, Persister, (IEventSource)Session);
136136
foreach (IPostInsertEventListener listener in postListeners)
137137
{
138138
await (listener.OnPostInsertAsync(postEvent, cancellationToken)).ConfigureAwait(false);
@@ -147,7 +147,7 @@ private async Task<bool> PreInsertAsync(CancellationToken cancellationToken)
147147
bool veto = false;
148148
if (preListeners.Length > 0)
149149
{
150-
var preEvent = new PreInsertEvent(Instance, Id, state, Persister, (IEventSource) Session);
150+
var preEvent = new PreInsertEvent(Instance, Id, State, Persister, (IEventSource) Session);
151151
foreach (IPreInsertEventListener listener in preListeners)
152152
{
153153
veto |= await (listener.OnPreInsertAsync(preEvent, cancellationToken)).ConfigureAwait(false);

src/NHibernate/Engine/ActionQueue.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public partial class ActionQueue
3030
// Object insertions, updates, and deletions have list semantics because
3131
// they must happen in the right order so as to respect referential
3232
// integrity
33-
private readonly List<IExecutable> insertions;
33+
private readonly List<AbstractEntityInsertAction> insertions;
3434
private readonly List<EntityDeleteAction> deletions;
3535
private readonly List<EntityUpdateAction> updates;
3636
// Actually the semantics of the next three are really "Bag"
@@ -48,7 +48,7 @@ public partial class ActionQueue
4848
public ActionQueue(ISessionImplementor session)
4949
{
5050
this.session = session;
51-
insertions = new List<IExecutable>(InitQueueListSize);
51+
insertions = new List<AbstractEntityInsertAction>(InitQueueListSize);
5252
deletions = new List<EntityDeleteAction>(InitQueueListSize);
5353
updates = new List<EntityUpdateAction>(InitQueueListSize);
5454

@@ -550,7 +550,7 @@ private class InsertActionSorter
550550
private readonly Dictionary<object, int> _entityBatchDependency = new Dictionary<object, int>();
551551

552552
// the map of batch numbers to EntityInsertAction lists
553-
private readonly Dictionary<int, List<EntityInsertAction>> _actionBatches = new Dictionary<int, List<EntityInsertAction>>();
553+
private readonly Dictionary<int, List<AbstractEntityInsertAction>> _actionBatches = new Dictionary<int, List<AbstractEntityInsertAction>>();
554554

555555
/// <summary>
556556
/// A sorter aiming to group inserts as much as possible for optimizing batching.
@@ -572,7 +572,7 @@ public InsertActionSorter(ActionQueue actionQueue)
572572
public void Sort()
573573
{
574574
// build the map of entity names that indicate the batch number
575-
foreach (EntityInsertAction action in _actionQueue.insertions)
575+
foreach (var action in _actionQueue.insertions)
576576
{
577577
var entityName = action.EntityName;
578578

@@ -598,7 +598,7 @@ public void Sort()
598598
}
599599
}
600600

601-
private int GetBatchNumber(EntityInsertAction action, string entityName)
601+
private int GetBatchNumber(AbstractEntityInsertAction action, string entityName)
602602
{
603603
int batchNumber;
604604
if (_latestBatches.TryGetValue(entityName, out batchNumber))
@@ -620,7 +620,7 @@ private int GetBatchNumber(EntityInsertAction action, string entityName)
620620
return batchNumber;
621621
}
622622

623-
private bool RequireNewBatch(EntityInsertAction action, int latestBatchNumberForType)
623+
private bool RequireNewBatch(AbstractEntityInsertAction action, int latestBatchNumberForType)
624624
{
625625
// This method assumes the original action list is already sorted in order to respect dependencies.
626626
var propertyValues = action.State;
@@ -658,20 +658,20 @@ private bool RequireNewBatch(EntityInsertAction action, int latestBatchNumberFor
658658
return false;
659659
}
660660

661-
private void AddToBatch(int batchNumber, EntityInsertAction action)
661+
private void AddToBatch(int batchNumber, AbstractEntityInsertAction action)
662662
{
663-
List<EntityInsertAction> actions;
663+
List<AbstractEntityInsertAction> actions;
664664

665665
if (!_actionBatches.TryGetValue(batchNumber, out actions))
666666
{
667-
actions = new List<EntityInsertAction>();
667+
actions = new List<AbstractEntityInsertAction>();
668668
_actionBatches[batchNumber] = actions;
669669
}
670670

671671
actions.Add(action);
672672
}
673673

674-
private void UpdateChildrenDependencies(int batchNumber, EntityInsertAction action)
674+
private void UpdateChildrenDependencies(int batchNumber, AbstractEntityInsertAction action)
675675
{
676676
var propertyValues = action.State;
677677
var propertyTypes = action.Persister.EntityMetamodel?.PropertyTypes;

0 commit comments

Comments
 (0)