Skip to content

Commit f4fc256

Browse files
committed
Issue #75 Add Section in README
1 parent cbbcd79 commit f4fc256

7 files changed

Lines changed: 159 additions & 20 deletions

README.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,101 @@ For example:
137137
.Map("geo", x => x.geo, NpgsqlDbType.Point)
138138
```
139139

140+
## Mapping Composite Types ##
141+
142+
Imagine you have a composite type called ``person_type`` in a schema of your database:
143+
144+
```sql
145+
create type sample.person_type as
146+
(
147+
first_name text,
148+
last_name text,
149+
birth_date date
150+
);
151+
```
152+
153+
And it is used in a table called ``CompositeTest``:
154+
155+
```sql
156+
create table sample.CompositeTest
157+
(
158+
col_text text,
159+
col_person sample.person_type
160+
)
161+
```
162+
163+
You first need to map the Postgres ``person_type`` to a C\# class:
164+
165+
```csharp
166+
private class PersonType
167+
{
168+
public string FirstName { get; set; }
169+
170+
public string LastName { get; set; }
171+
172+
public DateTime BirthDate { get; set; }
173+
}
174+
```
175+
176+
A hint: Npgsql always converts the property name to a snake case column name, so ``FirstName`` is mapped
177+
to ``first_name`` by convention. You can use the ``[PgName]`` attribute to explicitly set the Postgres type
178+
name.
179+
180+
Next the table is mapped to the following C\# model:
181+
182+
```csharp
183+
private class SampleEntity
184+
{
185+
public string TextColumn { get; set; }
186+
187+
public PersonType CompositeTypeColumn { get; set; }
188+
}
189+
```
190+
191+
And now we can bulk write ``SampleEntity`` instances using PostgreSQLCopyHelper like this:
192+
193+
```csharp
194+
connection.TypeMapper.MapComposite<PersonType>("sample.person_type");
195+
196+
// ... alternatively you can set it globally at any place in your application using the NpgsqlConnection.GlobalTypeMapper:
197+
//
198+
// NpgsqlConnection.GlobalTypeMapper.MapComposite<PersonType>("sample.person_type");
199+
200+
var subject = new PostgreSQLCopyHelper<SampleEntity>("sample", "CompositeTest")
201+
.MapText("col_text", x => x.TextColumn)
202+
.Map("col_person", x => x.CompositeTypeColumn);
203+
204+
var entities = new List<SampleEntity>();
205+
206+
entities.Add(new SampleEntity
207+
{
208+
TextColumn = "0",
209+
CompositeTypeColumn = new PersonType { FirstName = "Fake", LastName = "Fakerton", BirthDate = new DateTime(1987, 1, 11) }
210+
});
211+
212+
entities.Add(new SampleEntity
213+
{
214+
TextColumn = "1",
215+
CompositeTypeColumn = new PersonType { FirstName = "Philipp", LastName = "Wagner", BirthDate = new DateTime(1912, 1, 11) }
216+
});
217+
218+
subject.SaveAll(connection, entities);
219+
220+
```
221+
222+
In the listing you see, that we need to tell Npgsql how to map the Postgres type using ``MapComposite<>``. This can
223+
be done per Connection like this:
224+
225+
```
226+
connection.TypeMapper.MapComposite<PersonType>("sample.person_type");
227+
```
228+
229+
Or you can alternatively set the Mapping globally at any place in your application using the ``NpgsqlConnection.GlobalTypeMapper``:
230+
231+
```
232+
NpgsqlConnection.GlobalTypeMapper.MapComposite<PersonType>("sample.person_type");
233+
```
234+
140235
## PostgreSQLCopyHelper.NodaTime: NodaTime Support ##
141236

142237
The [PostgreSQLCopyHelper.NodaTime](https://www.nuget.org/packages/PostgreSQLCopyHelper.NodaTime/) package extends PostgreSQLCopyHelper for [NodaTime](https://nodatime.org/) types.
34.7 KB
Binary file not shown.
69.9 KB
Binary file not shown.
9.73 KB
Binary file not shown.
24.9 KB
Binary file not shown.

src/PostgreSQLCopyHelper.Test/Extensions/NpgsqlExtensions.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,27 @@ public static IList<object[]> GetAll(this NpgsqlConnection connection, string sc
2929

3030
return result;
3131
}
32+
33+
public static IList<object[]> GetAll(this NpgsqlConnection connection, string sqlStatement)
34+
{
35+
var sqlCommand = new NpgsqlCommand(sqlStatement, connection);
36+
37+
var result = new List<object[]>();
38+
using (var dataReader = sqlCommand.ExecuteReader())
39+
{
40+
while (dataReader.Read())
41+
{
42+
var values = new object[dataReader.FieldCount];
43+
for (var i = 0; i < dataReader.FieldCount; i++)
44+
{
45+
values[i] = dataReader[i];
46+
}
47+
result.Add(values);
48+
}
49+
}
50+
51+
return result;
52+
}
53+
3254
}
3355
}

src/PostgreSQLCopyHelper.Test/Issues/Issue75_CompositeTypes_Test.cs

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,23 @@ namespace PostgreSQLCopyHelper.Test.Issues
1313
[TestFixture]
1414
public class Issue75_CompositeTypes_Test : TransactionalTestBase
1515
{
16+
private class SampleEntity
17+
{
18+
public string TextColumn { get; set; }
19+
20+
public PersonType CompositeTypeColumn { get; set; }
21+
}
22+
1623
private class PersonType
1724
{
18-
[PgName("first_name")]
1925
public string FirstName { get; set; }
2026

21-
[PgName("last_name")]
2227
public string LastName { get; set; }
2328

24-
[PgName("birth_date")]
2529
public DateTime BirthDate { get; set; }
2630
}
2731

28-
private PostgreSQLCopyHelper<PersonType> subject;
32+
private PostgreSQLCopyHelper<SampleEntity> subject;
2933

3034
protected override void OnSetupInTransaction()
3135
{
@@ -45,31 +49,49 @@ public void Test_CompositeBulkInsert()
4549

4650
connection.TypeMapper.MapComposite<PersonType>("sample.person_type");
4751

48-
subject = new PostgreSQLCopyHelper<PersonType>("sample", "CompositeTest")
49-
.Map("col_person", x => x);
52+
// ... alternatively you can set it globally at any place in your application using the NpgsqlConnection.GlobalTypeMapper:
53+
//
54+
// NpgsqlConnection.GlobalTypeMapper.MapComposite<PersonType>("sample.person_type");
5055

51-
var entities = new List<PersonType>();
56+
subject = new PostgreSQLCopyHelper<SampleEntity>("sample", "CompositeTest")
57+
.MapText("col_text", x => x.TextColumn)
58+
.Map("col_person", x => x.CompositeTypeColumn);
5259

53-
entities.Add(new PersonType { FirstName = "Philipp", LastName = "Wagner", BirthDate = new DateTime(1912, 1, 11) });
54-
entities.Add(new PersonType { FirstName = "Fake", LastName = "Fakerton", BirthDate = new DateTime(1987, 1, 11) });
60+
var entities = new List<SampleEntity>();
61+
62+
entities.Add(new SampleEntity
63+
{
64+
TextColumn = "0",
65+
CompositeTypeColumn = new PersonType { FirstName = "Fake", LastName = "Fakerton", BirthDate = new DateTime(1987, 1, 11) }
66+
});
67+
68+
entities.Add(new SampleEntity
69+
{
70+
TextColumn = "1",
71+
CompositeTypeColumn = new PersonType { FirstName = "Philipp", LastName = "Wagner", BirthDate = new DateTime(1912, 1, 11) }
72+
});
5573

56-
// Try to work with the Bulk Inserter:
5774
subject.SaveAll(connection, entities);
5875

59-
var result = connection.GetAll("sample", "CompositeTest")
60-
.Select(x => (PersonType) x[0])
61-
.OrderBy(x => x.FirstName)
76+
var result = connection.GetAll("SELECT col_text, col_person from sample.CompositeTest")
77+
.Select(x => new SampleEntity {
78+
TextColumn = (string) x[0],
79+
CompositeTypeColumn = (PersonType) x[1]
80+
})
81+
.OrderBy(x => x.TextColumn)
6282
.ToList();
6383

6484
Assert.AreEqual(2, result.Count);
6585

66-
Assert.AreEqual("Fake", result[0].FirstName);
67-
Assert.AreEqual("Fakerton", result[0].LastName);
68-
Assert.AreEqual(new DateTime(1987, 1, 11), result[0].BirthDate);
86+
Assert.AreEqual("0", result[0].TextColumn);
87+
Assert.AreEqual("Fake", result[0].CompositeTypeColumn.FirstName);
88+
Assert.AreEqual("Fakerton", result[0].CompositeTypeColumn.LastName);
89+
Assert.AreEqual(new DateTime(1987, 1, 11), result[0].CompositeTypeColumn.BirthDate);
6990

70-
Assert.AreEqual("Philipp", result[1].FirstName);
71-
Assert.AreEqual("Wagner", result[1].LastName);
72-
Assert.AreEqual(new DateTime(1912, 1, 11), result[1].BirthDate);
91+
Assert.AreEqual("1", result[1].TextColumn);
92+
Assert.AreEqual("Philipp", result[1].CompositeTypeColumn.FirstName);
93+
Assert.AreEqual("Wagner", result[1].CompositeTypeColumn.LastName);
94+
Assert.AreEqual(new DateTime(1912, 1, 11), result[1].CompositeTypeColumn.BirthDate);
7395
}
7496

7597
private void CreateTableAndType()
@@ -89,6 +111,7 @@ birth_date date
89111
{
90112
var sqlStatement = @"CREATE TABLE sample.CompositeTest
91113
(
114+
col_text text,
92115
col_person sample.person_type
93116
);";
94117

@@ -112,7 +135,6 @@ private void DropTableAndType()
112135

113136
sqlCommand.ExecuteNonQuery();
114137
}
115-
116138
}
117139
}
118140
}

0 commit comments

Comments
 (0)