-
Notifications
You must be signed in to change notification settings - Fork 2k
/
ValueObjectCollection.cs
132 lines (110 loc) · 4.34 KB
/
ValueObjectCollection.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Diagnostics;
namespace EFModeling.ValueConversions;
public class ValueObjectCollection : Program
{
public void Run()
{
ConsoleWriteLines("Sample showing value conversions for a collection of value objects...");
using (var context = new SampleDbContext())
{
CleanDatabase(context);
ConsoleWriteLines("Save a new entity...");
context.Add(
new Blog
{
Finances = new List<AnnualFinance>
{
new AnnualFinance(2018, new Money(326.65m, Currency.UsDollars), new Money(125m, Currency.UsDollars)),
new AnnualFinance(2019, new Money(112.20m, Currency.UsDollars), new Money(125m, Currency.UsDollars)),
new AnnualFinance(2020, new Money(25.77m, Currency.UsDollars), new Money(125m, Currency.UsDollars))
}
});
context.SaveChanges();
}
using (var context = new SampleDbContext())
{
ConsoleWriteLines("Read the entity back...");
var blog = context.Set<Blog>().Single();
ConsoleWriteLines($"Blog with finances {string.Join(", ", blog.Finances.Select(f => $"{f.Year}: I={f.Income} E={f.Expenses} R={f.Revenue}"))}.");
ConsoleWriteLines("Changing the value object and saving again");
blog.Finances.Add(new AnnualFinance(2021, new Money(12.0m, Currency.UsDollars), new Money(125m, Currency.UsDollars)));
context.SaveChanges();
}
ConsoleWriteLines("Sample finished.");
}
public class SampleDbContext : DbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
#region ConfigureValueObjectCollection
modelBuilder.Entity<Blog>()
.Property(e => e.Finances)
.HasConversion(
v => JsonSerializer.Serialize(v, (JsonSerializerOptions)null),
v => JsonSerializer.Deserialize<List<AnnualFinance>>(v, (JsonSerializerOptions)null),
new ValueComparer<IList<AnnualFinance>>(
(c1, c2) => c1.SequenceEqual(c2),
c => c.Aggregate(0, (a, v) => HashCode.Combine(a, v.GetHashCode())),
c => (IList<AnnualFinance>)c.ToList()));
#endregion
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.LogTo(Console.WriteLine, new[] { RelationalEventId.CommandExecuted })
.UseSqlite("DataSource=test.db")
.EnableSensitiveDataLogging();
}
#region ValueObjectCollection
public readonly struct AnnualFinance
{
[JsonConstructor]
public AnnualFinance(int year, Money income, Money expenses)
{
Year = year;
Income = income;
Expenses = expenses;
}
public int Year { get; }
public Money Income { get; }
public Money Expenses { get; }
public Money Revenue => new Money(Income.Amount - Expenses.Amount, Income.Currency);
}
#endregion
#region ValueObjectCollectionMoney
public readonly struct Money
{
[JsonConstructor]
public Money(decimal amount, Currency currency)
{
Amount = amount;
Currency = currency;
}
public override string ToString()
=> (Currency == Currency.UsDollars ? "$" : "£") + Amount;
public decimal Amount { get; }
public Currency Currency { get; }
}
public enum Currency
{
UsDollars,
PoundsSterling
}
#endregion
#region ValueObjectCollectionModel
public class Blog
{
public int Id { get; set; }
public string Name { get; set; }
public IList<AnnualFinance> Finances { get; set; }
}
#endregion
}