Skip to content

Commit b5440cc

Browse files
committed
Add ability to store dynamic component in any format
1 parent ff6fed0 commit b5440cc

File tree

3 files changed

+63
-67
lines changed

3 files changed

+63
-67
lines changed

src/NHibernate.Test/NHSpecificTest/NH2664Dynamic/Fixture.cs

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Linq;
33
using NUnit.Framework;
44
using System.Collections.Generic;
5+
using System.Dynamic;
56
using System.Linq.Dynamic.Core;
67

78
namespace NHibernate.Test.NHSpecificTest.NH2664Dynamic
@@ -22,37 +23,38 @@ protected override void OnSetUp()
2223
using (var session = OpenSession())
2324
using (var tran = session.BeginTransaction())
2425
{
26+
var properties1 = new Dictionary<string, object>
27+
{
28+
["Name"] = "First Product",
29+
["Description"] = "First Description"
30+
};
2531
session.Save(
2632
new Product
2733
{
2834
ProductId = "1",
29-
Properties = new Dictionary<string, object>
30-
{
31-
["Name"] = "First Product",
32-
["Description"] = "First Description"
33-
}
35+
Properties = properties1
3436
});
3537

38+
var properties2 = new
39+
{
40+
Name = "Second Product",
41+
Description = "Second Description"
42+
};
3643
session.Save(
3744
new Product
3845
{
3946
ProductId = "2",
40-
Properties = new Dictionary<string, object>
41-
{
42-
["Name"] = "Second Product",
43-
["Description"] = "Second Description"
44-
}
47+
Properties = properties2
4548
});
4649

50+
dynamic properties3 = new ExpandoObject();
51+
properties3.Name = "Third Product";
52+
properties3.Description = "Third Description";
4753
session.Save(
4854
new Product
4955
{
5056
ProductId = "3",
51-
Properties = new Dictionary<string, object>
52-
{
53-
["Name"] = "val",
54-
["Description"] = "val"
55-
}
57+
Properties = properties3
5658
});
5759

5860
tran.Commit();

src/NHibernate/NHibernate.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
<Reference Include="System.ServiceModel" />
5050
<Reference Include="System.Transactions" />
5151
<Reference Include="System.Configuration" />
52+
<Reference Include="Microsoft.CSharp" />
5253
</ItemGroup>
5354

5455
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp2.0'">
@@ -63,6 +64,7 @@
6364
<PackageReference Include="System.Security.Permissions" Version="4.4.1" />
6465
<PackageReference Include="System.Reflection.Emit" Version="4.3.0" />
6566
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.3.0" />
67+
<PackageReference Include="Microsoft.CSharp" Version="4.4.1" />
6668
</ItemGroup>
6769

6870
<ItemGroup>

src/NHibernate/Properties/MapAccessor.cs

Lines changed: 44 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,87 +2,79 @@
22
using System.Reflection;
33
using NHibernate.Engine;
44
using System;
5+
using System.Collections.Concurrent;
6+
using System.Collections.Generic;
7+
using System.Runtime.CompilerServices;
8+
using Microsoft.CSharp.RuntimeBinder;
9+
using Binder = Microsoft.CSharp.RuntimeBinder.Binder;
10+
511
namespace NHibernate.Properties
612
{
713
[Serializable]
814
public class MapAccessor : IPropertyAccessor
9-
{
10-
#region IPropertyAccessor Members
15+
{
16+
public IGetter GetGetter(System.Type theClass, string propertyName) => new MapGetter(propertyName);
1117

12-
public IGetter GetGetter(System.Type theClass, string propertyName)
13-
{
14-
return new MapGetter(propertyName);
15-
}
18+
public ISetter GetSetter(System.Type theClass, string propertyName) => new MapSetter(propertyName);
1619

17-
public ISetter GetSetter(System.Type theClass, string propertyName)
18-
{
19-
return new MapSetter(propertyName);
20-
}
20+
public bool CanAccessThroughReflectionOptimizer => false;
2121

22-
public bool CanAccessThroughReflectionOptimizer
23-
{
24-
get { return false; }
25-
}
26-
27-
#endregion
2822
[Serializable]
2923
public sealed class MapSetter : ISetter
3024
{
31-
private readonly string name;
25+
private readonly string _name;
3226

33-
internal MapSetter(string name)
34-
{
35-
this.name = name;
36-
}
27+
internal MapSetter(string name) => _name = name;
3728

38-
public MethodInfo Method
39-
{
40-
get { return null; }
41-
}
29+
public MethodInfo Method => null;
4230

43-
public string PropertyName
44-
{
45-
get { return null; }
46-
}
31+
public string PropertyName => null;
4732

4833
public void Set(object target, object value)
4934
{
50-
((IDictionary)target)[name] = value;
35+
((IDictionary) target)[_name] = value;
5136
}
5237
}
38+
5339
[Serializable]
5440
public sealed class MapGetter : IGetter
5541
{
56-
private readonly string name;
42+
private static readonly ConcurrentDictionary<string, CallSite<Func<CallSite, object, object>>> GetMemberSites =
43+
new ConcurrentDictionary<string, CallSite<Func<CallSite, object, object>>>();
5744

58-
internal MapGetter(string name)
59-
{
60-
this.name = name;
61-
}
45+
private readonly string _name;
6246

63-
public MethodInfo Method
64-
{
65-
get { return null; }
66-
}
47+
internal MapGetter(string name) => _name = name;
6748

68-
public object GetForInsert(object owner, IDictionary mergeMap, ISessionImplementor session)
69-
{
70-
return Get(owner);
71-
}
49+
public MethodInfo Method => null;
7250

73-
public string PropertyName
74-
{
75-
get { return null; }
76-
}
51+
public object GetForInsert(object owner, IDictionary mergeMap, ISessionImplementor session) => Get(owner);
7752

78-
public System.Type ReturnType
79-
{
80-
get { return typeof(object); }
81-
}
53+
public string PropertyName => null;
54+
55+
public System.Type ReturnType => typeof(object);
8256

8357
public object Get(object target)
8458
{
85-
return ((IDictionary)target)[name];
59+
switch (target)
60+
{
61+
case IDictionary d:
62+
return d[_name];
63+
case IDictionary<string, object> d:
64+
d.TryGetValue(_name, out var result);
65+
return result;
66+
default:
67+
var site = GetMemberSites.GetOrAdd(
68+
_name,
69+
name => CallSite<Func<CallSite, object, object>>.Create(
70+
Binder.GetMember(
71+
CSharpBinderFlags.None,
72+
name,
73+
target.GetType(),
74+
new[] {CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null)})));
75+
76+
return site.Target(site, target);
77+
}
8678
}
8779
}
8880
}

0 commit comments

Comments
 (0)