Skip to content

Commit 5b709dc

Browse files
committed
Update ExecuteDeferredQuery to map columns to nested object properties. Add test fixture to to assert correct mappings.
1 parent 91c17ad commit 5b709dc

File tree

4 files changed

+218
-6
lines changed

4 files changed

+218
-6
lines changed

src/SQLite.cs

+37-6
Original file line numberDiff line numberDiff line change
@@ -2817,23 +2817,54 @@ public IEnumerable<T> ExecuteDeferredQuery<T> (TableMapping map)
28172817
_conn.Tracer?.Invoke ("Executing Query: " + this);
28182818
}
28192819

2820+
var values = new Dictionary<int, Tuple<string, string>> ();
28202821
var stmt = Prepare ();
28212822
try {
28222823
var cols = new TableMapping.Column[SQLite3.ColumnCount (stmt)];
28232824

28242825
for (int i = 0; i < cols.Length; i++) {
28252826
var name = SQLite3.ColumnName16 (stmt, i);
2826-
cols[i] = map.FindColumn (name);
2827+
if (name.Contains (".")) {
2828+
var properties = name.Split ('.');
2829+
if (properties.Length == 2)
2830+
values[i] = Tuple.Create (properties[0], properties[1]);
2831+
}
2832+
else {
2833+
cols[i] = map.FindColumn (name);
2834+
}
28272835
}
28282836

28292837
while (SQLite3.Step (stmt) == SQLite3.Result.Row) {
28302838
var obj = Activator.CreateInstance (map.MappedType);
28312839
for (int i = 0; i < cols.Length; i++) {
2832-
if (cols[i] == null)
2833-
continue;
2834-
var colType = SQLite3.ColumnType (stmt, i);
2835-
var val = ReadCol (stmt, i, colType, cols[i].ColumnType);
2836-
cols[i].SetValue (obj, val);
2840+
if (cols[i] == null) {
2841+
if (!values.ContainsKey (i))
2842+
continue;
2843+
2844+
var valueStore = values[i];
2845+
string propertyName = valueStore.Item1;
2846+
string subPropertyName = valueStore.Item2;
2847+
var column = map.Columns.FirstOrDefault (x => x.Name == propertyName);
2848+
var property = column?.ColumnType?.GetRuntimeProperty (subPropertyName);
2849+
if (column is null || property is null)
2850+
continue;
2851+
2852+
var colType = SQLite3.ColumnType (stmt, i);
2853+
var val = ReadCol (stmt, i, colType, property.PropertyType);
2854+
var nestedObject = (obj.GetType ().GetRuntimeProperty (propertyName)).GetValue (obj);
2855+
if (nestedObject is null) {
2856+
var newObjectType = (obj.GetType ().GetRuntimeProperty (propertyName)).PropertyType;
2857+
nestedObject = Activator.CreateInstance (newObjectType);
2858+
(obj.GetType ().GetRuntimeProperty (propertyName)).SetValue (obj, nestedObject);
2859+
}
2860+
var nestedObjectProperty = nestedObject?.GetType ().GetRuntimeProperty (subPropertyName);
2861+
nestedObjectProperty?.SetValue (nestedObject, val);
2862+
}
2863+
else {
2864+
var colType = SQLite3.ColumnType (stmt, i);
2865+
var val = ReadCol (stmt, i, colType, cols[i].ColumnType);
2866+
cols[i].SetValue (obj, val);
2867+
}
28372868
}
28382869
OnInstanceCreated (obj);
28392870
yield return (T)obj;
+177
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
#if NETFX_CORE
5+
using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
6+
using SetUp = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestInitializeAttribute;
7+
using TestFixture = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestClassAttribute;
8+
using Test = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestMethodAttribute;
9+
#else
10+
using NUnit.Framework;
11+
#endif
12+
13+
namespace SQLite.Tests
14+
{
15+
[TestFixture]
16+
public class NestedObjectPropertyMappingTest
17+
{
18+
SQLiteConnection db;
19+
20+
int fooId = 1;
21+
int fooReferenceId = 3;
22+
string fooName = "Foo Table";
23+
string fooDescription = "The main table.";
24+
string fooReferenceName = "Referenced table.";
25+
string fooReferenceDescription = "A table referenced by the main table";
26+
27+
class FooTable
28+
{
29+
[PrimaryKey]
30+
public int Id { get; set; }
31+
32+
public string FooName { get; set; }
33+
34+
public string FooDescription { get; set; }
35+
36+
public int FooTableReferenceId { get; set; }
37+
}
38+
39+
class FooTableReference
40+
{
41+
[PrimaryKey]
42+
public int Id { get; set; }
43+
44+
public string ReferenceName { get; set; }
45+
46+
public string ReferenceDescription { get; set; }
47+
}
48+
49+
class FooDTO
50+
{
51+
public int Id { get; set; }
52+
53+
public string Name { get; set; }
54+
55+
public string Description { get; set; }
56+
57+
public FooNestedObject NestedObject { get; set; }
58+
}
59+
60+
class FooNestedObject
61+
{
62+
public int Id { get; set; }
63+
64+
public string NestedName { get; set; }
65+
66+
public string NestedDescription { get; set; }
67+
68+
public FooNestedObject NestedChild { get; set; }
69+
}
70+
71+
public NestedObjectPropertyMappingTest()
72+
{
73+
SetupDb ();
74+
}
75+
76+
void SetupDb()
77+
{
78+
db = new TestDb ();
79+
80+
db.CreateTable<FooTable> ();
81+
db.CreateTable<FooTableReference> ();
82+
83+
db.Insert (new FooTable {
84+
Id = fooId,
85+
FooName = fooName,
86+
FooDescription = fooDescription,
87+
FooTableReferenceId = fooReferenceId
88+
});
89+
db.Insert (new FooTableReference {
90+
Id = fooReferenceId,
91+
ReferenceName = fooReferenceName,
92+
ReferenceDescription = fooReferenceDescription,
93+
});
94+
}
95+
96+
[Test]
97+
public void SelectNestedObject ()
98+
{
99+
string query =
100+
$" select" +
101+
$" fooTable.{nameof (FooTable.Id)} as '{nameof (FooDTO.Id)}'," +
102+
$" fooTable.{nameof (FooTable.FooName)} as '{nameof (FooDTO.Name)}'," +
103+
$" fooTable.{nameof (FooTable.FooDescription)} as '{nameof (FooDTO.Description)}'," +
104+
$" fooTableReference.{nameof (FooTableReference.Id)} as '{nameof (FooDTO.NestedObject)}.{nameof (FooNestedObject.Id)}'," +
105+
$" fooTableReference.{nameof (FooTableReference.ReferenceName)} as '{nameof (FooDTO.NestedObject)}.{nameof (FooNestedObject.NestedName)}'," +
106+
$" fooTableReference.{nameof (FooTableReference.ReferenceDescription)} as '{nameof (FooDTO.NestedObject)}.{nameof (FooNestedObject.NestedDescription)}'" +
107+
$" from {nameof (FooTable)} as fooTable" +
108+
$" join {nameof (FooTableReference)} fooTableReference on fooTable.{nameof (FooTable.FooTableReferenceId)} = fooTableReference.{nameof (FooTableReference.Id)}" +
109+
$" where fooTable.{nameof (FooTable.Id)} = {fooId}";
110+
var dtoArray = db.Query<FooDTO> (query);
111+
var dto = dtoArray[0];
112+
113+
Assert.AreEqual (dto.Id, fooId);
114+
Assert.AreEqual (dto.Name, fooName);
115+
Assert.AreEqual (dto.Description, fooDescription);
116+
Assert.IsNotNull (dto.NestedObject);
117+
Assert.AreEqual (dto.NestedObject.Id, fooReferenceId);
118+
Assert.AreEqual (dto.NestedObject.NestedName, fooReferenceName);
119+
Assert.AreEqual (dto.NestedObject.NestedDescription, fooReferenceDescription);
120+
}
121+
122+
[Test]
123+
public void SelectNestedObjectChildObjectProperty ()
124+
{
125+
string query =
126+
$" select" +
127+
$" fooTable.{nameof (FooTable.Id)} as '{nameof (FooDTO.Id)}'," +
128+
$" fooTable.{nameof (FooTable.FooName)} as '{nameof (FooDTO.Name)}'," +
129+
$" fooTable.{nameof (FooTable.FooDescription)} as '{nameof (FooDTO.Description)}'," +
130+
$" fooTableReference.{nameof (FooTableReference.Id)} as '{nameof (FooDTO.NestedObject)}.{nameof (FooNestedObject.Id)}'," +
131+
$" fooTableReference.{nameof (FooTableReference.ReferenceName)} as '{nameof (FooDTO.NestedObject)}.{nameof (FooNestedObject.NestedName)}'," +
132+
$" fooTableReference.{nameof (FooTableReference.ReferenceDescription)} as '{nameof (FooDTO.NestedObject)}.{nameof (FooNestedObject.NestedChild)}.{nameof (FooNestedObject.NestedDescription)}'" +
133+
$" from {nameof (FooTable)} as fooTable" +
134+
$" join {nameof (FooTableReference)} fooTableReference on fooTable.{nameof (FooTable.FooTableReferenceId)} = fooTableReference.{nameof (FooTableReference.Id)}" +
135+
$" where fooTable.{nameof (FooTable.Id)} = {fooId}";
136+
var dtoArray = db.Query<FooDTO> (query);
137+
var dto = dtoArray[0];
138+
139+
Assert.AreEqual (dto.Id, fooId);
140+
Assert.AreEqual (dto.Name, fooName);
141+
Assert.AreEqual (dto.Description, fooDescription);
142+
Assert.IsNotNull (dto.NestedObject);
143+
Assert.AreEqual (dto.NestedObject.Id, fooReferenceId);
144+
Assert.AreEqual (dto.NestedObject.NestedName, fooReferenceName);
145+
146+
//Does not map to a nested object of a nested object - only goes one level deep.
147+
Assert.IsNull (dto.NestedObject.NestedChild);
148+
}
149+
150+
[Test]
151+
public void SelectNonExistentNestedObjectProperty ()
152+
{
153+
string query =
154+
$" select" +
155+
$" fooTable.{nameof (FooTable.Id)} as '{nameof (FooDTO.Id)}'," +
156+
$" fooTable.{nameof (FooTable.FooName)} as '{nameof (FooDTO.Name)}'," +
157+
$" fooTable.{nameof (FooTable.FooDescription)} as '{nameof (FooDTO.Description)}'," +
158+
$" fooTableReference.{nameof (FooTableReference.Id)} as '{nameof (FooDTO.NestedObject)}.{nameof (FooNestedObject.Id)}'," +
159+
$" fooTableReference.{nameof (FooTableReference.ReferenceName)} as '{nameof (FooDTO.NestedObject)}.{nameof (FooNestedObject.NestedName)}'," +
160+
$" fooTableReference.{nameof (FooTableReference.ReferenceDescription)} as '{nameof (FooDTO.NestedObject)}.Foo'" +
161+
$" from {nameof (FooTable)} as fooTable" +
162+
$" join {nameof (FooTableReference)} fooTableReference on fooTable.{nameof (FooTable.FooTableReferenceId)} = fooTableReference.{nameof (FooTableReference.Id)}" +
163+
$" where fooTable.{nameof (FooTable.Id)} = {fooId}";
164+
var dtoArray = db.Query<FooDTO> (query);
165+
var dto = dtoArray[0];
166+
167+
Assert.AreEqual (dto.Id, fooId);
168+
Assert.AreEqual (dto.Name, fooName);
169+
Assert.AreEqual (dto.Description, fooDescription);
170+
Assert.IsNotNull (dto.NestedObject);
171+
Assert.AreEqual (dto.NestedObject.Id, fooReferenceId);
172+
Assert.AreEqual (dto.NestedObject.NestedName, fooReferenceName);
173+
Assert.IsNull (dto.NestedObject.NestedDescription);
174+
}
175+
}
176+
}
177+

tests/SQLite.Tests.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
<Compile Include="BackupTest.cs" />
8585
<Compile Include="ReadmeTest.cs" />
8686
<Compile Include="QueryTest.cs" />
87+
<Compile Include="NestedObjectPropertyMappingTest.cs" />
8788
</ItemGroup>
8889
<ItemGroup>
8990
<None Include="packages.config" />

tests/SQLite.Tests.iOS/SQLiteTestsiOS.csproj

+3
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@
153153
<Compile Include="..\QueryTest.cs">
154154
<Link>QueryTest.cs</Link>
155155
</Compile>
156+
<Compile Include="..\NestedObjectPropertyMappingTest.cs">
157+
<Link>NestedObjectPropertyMappingTest.cs</Link>
158+
</Compile>
156159
</ItemGroup>
157160
<Import Project="$(MSBuildExtensionsPath)\Xamarin\iOS\Xamarin.iOS.CSharp.targets" />
158161
</Project>

0 commit comments

Comments
 (0)