Skip to content

Commit 52a4bd4

Browse files
authored
Merge pull request #1778 from hazzik/dynamic-component
Allow to use dynamic objects as dynamic components
2 parents 33c1555 + 5df1fde commit 52a4bd4

File tree

18 files changed

+795
-42
lines changed

18 files changed

+795
-42
lines changed

doc/reference/modules/basic_mapping.xml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2680,9 +2680,10 @@
26802680
</para>
26812681

26822682
<para>
2683-
The <literal>&lt;dynamic-component&gt;</literal> element allows an <literal>IDictionary</literal>
2684-
or <literal>IDictionary&lt;string, object&gt;</literal> to be mapped as a component, where the
2685-
property names refer to keys of the dictionary. See <xref linkend="components-dynamic" />.
2683+
The <literal>&lt;dynamic-component&gt;</literal> element allows an <literal>IDictionary</literal>,
2684+
<literal>IDictionary&lt;string, object&gt;</literal>, or a C# <literal>dynamic</literal> to be mapped
2685+
as a component. When using dictionaries, the property names refer to keys of the dictionary. See
2686+
<xref linkend="components-dynamic" />.
26862687
</para>
26872688

26882689
</sect2>

doc/reference/modules/component_mapping.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,8 @@
342342

343343
<para>
344344
You can also map a property of type <literal>IDictionary</literal> or
345-
<literal>IDictionary&lt;string, object&gt;</literal>:
345+
<literal>IDictionary&lt;string, object&gt;</literal>, or declared as a C#
346+
<literal>dynamic</literal>:
346347
</para>
347348

348349
<programlisting><![CDATA[<dynamic-component name="UserAttributes">
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//------------------------------------------------------------------------------
2+
// <auto-generated>
3+
// This code was generated by AsyncGenerator.
4+
//
5+
// Changes to this file may cause incorrect behavior and will be lost if
6+
// the code is regenerated.
7+
// </auto-generated>
8+
//------------------------------------------------------------------------------
9+
10+
11+
using System;
12+
using System.Collections.Generic;
13+
using NUnit.Framework;
14+
15+
namespace NHibernate.Test.NHSpecificTest.NH1039Dynamic
16+
{
17+
using System.Threading.Tasks;
18+
[TestFixture]
19+
public class FixtureAsync : BugTestCase
20+
{
21+
protected override void OnTearDown()
22+
{
23+
using (var s = OpenSession())
24+
using (var tx = s.BeginTransaction())
25+
{
26+
s.Delete("from Person");
27+
tx.Commit();
28+
}
29+
}
30+
31+
[Test]
32+
public async Task TestAsync()
33+
{
34+
using (var s = OpenSession())
35+
using (var tx = s.BeginTransaction())
36+
{
37+
var person = new Person("1")
38+
{
39+
Name = "John Doe",
40+
Properties =
41+
{
42+
Phones = new HashSet<object> {"555-1234", "555-4321"}
43+
}
44+
};
45+
46+
await (s.SaveAsync(person));
47+
await (tx.CommitAsync());
48+
}
49+
50+
using (var s = OpenSession())
51+
using (s.BeginTransaction())
52+
{
53+
var person = (Person) await (s.CreateCriteria(typeof(Person)).UniqueResultAsync());
54+
55+
Assert.That(person.ID, Is.EqualTo("1"));
56+
Assert.That(person.Name, Is.EqualTo("John Doe"));
57+
var phones = person.Properties.Phones as ISet<object>;
58+
Assert.That(phones, Is.Not.Null);
59+
Assert.That(phones.Contains("555-1234"), Is.True);
60+
Assert.That(phones.Contains("555-4321"), Is.True);
61+
}
62+
}
63+
}
64+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
//------------------------------------------------------------------------------
2+
// <auto-generated>
3+
// This code was generated by AsyncGenerator.
4+
//
5+
// Changes to this file may cause incorrect behavior and will be lost if
6+
// the code is regenerated.
7+
// </auto-generated>
8+
//------------------------------------------------------------------------------
9+
10+
11+
using System.Collections;
12+
using System.Linq;
13+
using NUnit.Framework;
14+
using System.Collections.Generic;
15+
using System.Dynamic;
16+
using System.Linq.Dynamic.Core;
17+
using NHibernate.Linq;
18+
19+
namespace NHibernate.Test.NHSpecificTest.NH2664Dynamic
20+
{
21+
using System.Threading.Tasks;
22+
[TestFixture]
23+
public class FixtureAsync : TestCase
24+
{
25+
protected override string MappingsAssembly => "NHibernate.Test";
26+
27+
protected override string[] Mappings => new[] {"NHSpecificTest.NH2664Dynamic.Mappings.hbm.xml"};
28+
29+
/// <summary>
30+
/// push some data into the database
31+
/// Really functions as a save test also
32+
/// </summary>
33+
protected override void OnSetUp()
34+
{
35+
using (var session = OpenSession())
36+
using (var tran = session.BeginTransaction())
37+
{
38+
var properties1 = new Dictionary<string, object>
39+
{
40+
["Name"] = "First Product",
41+
["Description"] = "First Description"
42+
};
43+
session.Save(
44+
new Product
45+
{
46+
ProductId = "1",
47+
Properties = properties1
48+
});
49+
50+
var properties2 = new
51+
{
52+
Name = "Second Product",
53+
Description = "Second Description"
54+
};
55+
session.Save(
56+
new Product
57+
{
58+
ProductId = "2",
59+
Properties = properties2
60+
});
61+
62+
dynamic properties3 = new ExpandoObject();
63+
properties3.Name = "Third Product";
64+
properties3.Description = "Third Description";
65+
session.Save(
66+
new Product
67+
{
68+
ProductId = "3",
69+
Properties = properties3
70+
});
71+
72+
tran.Commit();
73+
}
74+
}
75+
76+
protected override void OnTearDown()
77+
{
78+
using (var session = OpenSession())
79+
using (var tran = session.BeginTransaction())
80+
{
81+
session.CreateQuery("delete from Product").ExecuteUpdate();
82+
tran.Commit();
83+
}
84+
}
85+
86+
[Test]
87+
public async Task Query_DynamicComponentAsync()
88+
{
89+
using (var session = OpenSession())
90+
{
91+
var product = await (session
92+
.Query<Product>()
93+
.Where("Properties.Name == @0", "First Product")
94+
.SingleAsync());
95+
96+
Assert.That(product, Is.Not.Null);
97+
Assert.That((object) product.Properties["Name"], Is.EqualTo("First Product"));
98+
Assert.That((object) product.Properties.Name, Is.EqualTo("First Product"));
99+
}
100+
}
101+
102+
[Test]
103+
public async Task Multiple_Query_Does_Not_CacheAsync()
104+
{
105+
using (var session = OpenSession())
106+
{
107+
// Query by name
108+
var product1 = await (session.Query<Product>().Where("Properties.Name == @0", "First Product").SingleAsync());
109+
Assert.That(product1.ProductId, Is.EqualTo("1"));
110+
111+
// Query by description (this test is to verify that the dictionary
112+
// index isn't cached from the query above.
113+
var product2 = await (session.Query<Product>().Where("Properties.Description == @0", "Second Description").SingleAsync());
114+
Assert.That(product2.ProductId, Is.EqualTo("2"));
115+
}
116+
}
117+
}
118+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using NUnit.Framework;
4+
5+
namespace NHibernate.Test.NHSpecificTest.NH1039Dynamic
6+
{
7+
[TestFixture]
8+
public class Fixture : BugTestCase
9+
{
10+
protected override void OnTearDown()
11+
{
12+
using (var s = OpenSession())
13+
using (var tx = s.BeginTransaction())
14+
{
15+
s.Delete("from Person");
16+
tx.Commit();
17+
}
18+
}
19+
20+
[Test]
21+
public void Test()
22+
{
23+
using (var s = OpenSession())
24+
using (var tx = s.BeginTransaction())
25+
{
26+
var person = new Person("1")
27+
{
28+
Name = "John Doe",
29+
Properties =
30+
{
31+
Phones = new HashSet<object> {"555-1234", "555-4321"}
32+
}
33+
};
34+
35+
s.Save(person);
36+
tx.Commit();
37+
}
38+
39+
using (var s = OpenSession())
40+
using (s.BeginTransaction())
41+
{
42+
var person = (Person) s.CreateCriteria(typeof(Person)).UniqueResult();
43+
44+
Assert.That(person.ID, Is.EqualTo("1"));
45+
Assert.That(person.Name, Is.EqualTo("John Doe"));
46+
var phones = person.Properties.Phones as ISet<object>;
47+
Assert.That(phones, Is.Not.Null);
48+
Assert.That(phones.Contains("555-1234"), Is.True);
49+
Assert.That(phones.Contains("555-4321"), Is.True);
50+
}
51+
}
52+
}
53+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
3+
namespace="NHibernate.Test.NHSpecificTest.NH1039Dynamic"
4+
assembly="NHibernate.Test">
5+
6+
<class name="Person" table="NH1039_Person">
7+
<id name="ID" type="string" length="32">
8+
<generator class="assigned"/>
9+
</id>
10+
11+
<property name="Name"/>
12+
13+
<dynamic-component name="Properties">
14+
<set name="Phones" table="NH1039_Phone">
15+
<key column="PersonId"/>
16+
<element column="`Number`" type="string"/>
17+
</set>
18+
</dynamic-component>
19+
</class>
20+
21+
</hibernate-mapping>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Dynamic;
5+
using System.Text;
6+
7+
namespace NHibernate.Test.NHSpecificTest.NH1039Dynamic
8+
{
9+
public class Person
10+
{
11+
public Person()
12+
{
13+
}
14+
15+
public Person(string id)
16+
{
17+
ID = id;
18+
}
19+
20+
public virtual string ID { get; set; }
21+
22+
public virtual string Name { get; set; }
23+
24+
public virtual dynamic Properties { get; set; } = new ExpandoObject();
25+
}
26+
}

0 commit comments

Comments
 (0)