Edition 0 Updated to asp. Net core 0


Value object implementation in C#



Yüklə 11,82 Mb.
Pdf görüntüsü
səhifə187/288
tarix12.07.2023
ölçüsü11,82 Mb.
#136458
1   ...   183   184   185   186   187   188   189   190   ...   288
NET-Microservices-Architecture-for-Containerized-NET-Applications

Value object implementation in C# 
In terms of implementation, you can have a value object base class that has basic utility methods like 
equality based on the comparison between all the attributes (since a value object must not be based 
on identity) and other fundamental characteristics. The following example shows a value object base 
class used in the ordering microservice from eShopOnContainers. 
public
abstract
class
ValueObject 

protected
static
bool
EqualOperator
(ValueObject left, ValueObject right) 

if
(
ReferenceEquals
(left, 
null
) ^ 
ReferenceEquals
(right, 
null
)) 

return
false


return
ReferenceEquals
(left, right) || left.
Equals
(right); 

protected
static
bool
NotEqualOperator
(ValueObject left, ValueObject right) 

return
!(
EqualOperator
(left, right)); 

protected
abstract
IEnumerable<
object

GetEqualityComponents
(); 
public
override
bool
Equals
(
object
obj) 

if
(obj == 
null
|| obj.
GetType
() != 
GetType
()) 

return
false


var
other = (ValueObject)obj; 
return
this
.
GetEqualityComponents
().
SequenceEqual
(other.
GetEqualityComponents
()); 

public
override
int
GetHashCode
() 

return
GetEqualityComponents
() 
.
Select
(x => x != 
null
? x.
GetHashCode
() : 
0

.
Aggregate
((x, y) => x ^ y); 

// Other utility methods



216 
CHAPTER 6 | Tackle Business Complexity in a Microservice with DDD and CQRS Patterns 
The 
ValueObject
is an 
abstract class
type, but in this example, it doesn’t overload the 
==
and 
!=
operators. You could choose to do so, making comparisons delegate to the 
Equals
override. For 
example, consider the following operator overloads to the 
ValueObject
type: 
public
static
bool
operator
==(ValueObject one, ValueObject two) 

return
EqualOperator
(one, two); 

public
static
bool
operator
!=(ValueObject one, ValueObject two) 

return
NotEqualOperator
(one, two); 

You can use this class when implementing your actual value object, as with the 
Address
value object 
shown in the following example: 
public
class
Address : ValueObject 

public
String Street { 
get

private
set
; } 
public
String City { 
get

private
set
; } 
public
String State { 
get

private
set
; } 
public
String Country { 
get

private
set
; } 
public
String ZipCode { 
get

private
set
; } 
public
Address
() { } 
public
Address
(
string
street, 
string
city, 
string
state, 
string
country, 
string
zipcode) 

Street = street; 
City = city; 
State = state; 
Country = country; 
ZipCode = zipcode; 

protected
override
IEnumerable<
object

GetEqualityComponents
() 

// Using a yield return statement to return each element one at a time
yield
return
Street; 
yield
return
City; 
yield
return
State; 
yield
return
Country; 
yield
return
ZipCode; 


This value object implementation of 
Address
has no identity, and therefore no ID field is defined for it, 
either in the 
Address
class definition or the 
ValueObject
class definition. 
Having no ID field in a class to be used by Entity Framework (EF) was not possible until EF Core 2.0, 
which greatly helps to implement better value objects with no ID. That is precisely the explanation of 
the next section. 


217 
CHAPTER 6 | Tackle Business Complexity in a Microservice with DDD and CQRS Patterns 
It could be argued that value objects, being immutable, should be read-only (that is, have get-only 
properties), and that’s indeed true. However, value
objects are usually serialized and deserialized to go 
through message queues, and being read-only stops the deserializer from assigning values, so you 
just leave them as 
private set
, which is read-only enough to be practical. 
Value object comparison semantics 
Two instances of the 
Address
type can be compared using all the following methods: 
var
one = 
new
Address
(
"1 Microsoft Way"

"Redmond"

"WA"

"US"

"98052"
); 
var
two = 
new
Address
(
"1 Microsoft Way"

"Redmond"

"WA"

"US"

"98052"
); 
Console.
WriteLine
(EqualityComparer
.
Default
.
Equals
(one, two)); 
// True
Console.
WriteLine
(
object
.
Equals
(one, two)); 
// True
Console.
WriteLine
(one.
Equals
(two)); 
// True
Console.
WriteLine
(one == two); 
// True
When all the values are the same, the comparisons are correctly evaluated as 
true
. If you didn’t 
choose to overload the 
==
and 
!=
operators, then the last comparison of 
one == two
would evaluate 
as 
false
. For more information, see 
Overload ValueObject equality operators

How to persist value objects in the database with EF Core 2.0 and later 
You just saw how to define a value object in your domain model. But how can you actually persist it 
into the database using Entity Framework Core since it usually targets entities with identity? 
Background and older approaches using EF Core 1.1 
As background, a limitation when using EF Core 1.0 and 1.1 was that you could not use 
complex types
 
as defined in EF 6.x in the traditional .NET Framework. Therefore, if using EF Core 1.0 or 1.1, you 
needed to store your value object as an EF entity with an ID field. Then, so it looked more like a value 
object with no identity, you could hide its ID so you make clear that the identity of a value object is 
not important in the domain model. You could hide that ID by using the ID as a 
shadow property

Since that configuration for hiding the ID in the model is set up in the EF infrastructure level, it would 
be kind of transparent for your domain model. 
In the initial version of eShopOnContainers (.NET Core 1.1), the hidden ID needed by EF Core 
infrastructure was implemented in the following way in the DbContext level, using Fluent API at the 
infrastructure project. Therefore, the ID was hidden from the domain model point of view, but still 
present in the infrastructure. 
// Old approach with EF Core 1.1
// Fluent API within the OrderingContext:DbContext in the Infrastructure project
void
ConfigureAddress
(EntityTypeBuilder
 addressConfiguration) 

addressConfiguration.
ToTable
(
"address"
, DEFAULT_SCHEMA); 
addressConfiguration.
Property
<
int
>(
"Id"
)
// Id is a shadow property
.
IsRequired
(); 
addressConfiguration.
HasKey
(
"Id"
);
// Id is a shadow property



218 
CHAPTER 6 | Tackle Business Complexity in a Microservice with DDD and CQRS Patterns 
However, the persistence of that value object into the database was performed like a regular entity in 
a different table. 
With EF Core 2.0 and later, there are new and better ways to persist value objects. 

Yüklə 11,82 Mb.

Dostları ilə paylaş:
1   ...   183   184   185   186   187   188   189   190   ...   288




Verilənlər bazası müəlliflik hüququ ilə müdafiə olunur ©azkurs.org 2024
rəhbərliyinə müraciət

gir | qeydiyyatdan keç
    Ana səhifə


yükləyin