How are aggregates instantiated to test other aggregates with?
Suppose I have an aggregate that, for some operation, requires the existence of another aggregate. Let's assume I have a car
and a garage
. There might be a command called ParkInGarage
that looks like this:
public class ParkInGarage {
@TargetAggregateIdentifier
public final UUID carId;
public final Garage garage;
//... constructor omitted
}
I've read that to validate the existence of an aggregate, it is good practice to use the loaded aggregate in commands since that already implies its existence (as opposed to passing a garageId
).
Now when unit-testing the Car
using Axon's fixtures, I can not simply instantiate my Garage
by saying new Garage(buildGarageCmd)
. It will say:
java.lang.IllegalStateException: Cannot request current Scope if none is active
Because no infrastructure was set up.
How would I test such a case, or should I design the aggregate differently?
Abstracted, real-world example
The aggregate root I am working with may have a reference to itself to form a tree-structure of said aggregate root. Let's call it Node
.
@Aggregate
public class Node {
private Node parentNode;
}
Upon creation, I can pass an Optional<Node>
as parent, or set the parent at a later time using a separate command. Whether the parent should be defined as instance or by ID is part of the question.
public class AttachNodeCmd {
@TargetAggregateIdentifier
public final UUID nodeId;
public final Optional<Node> parentNode;
}
In the command handler, I need to check if attaching the node to given parent would introduce a cycle (the structure is supposed to be a tree, not a common graph).
@CommandHandler
public Node(AttachNodeCmd command) {
if (command.parentNode.isPresent()) {
Node currentNode = command.parentNode.get();
while (currentNode != null) {
if (currentNode.equals(this)) throw new RecursionException();
currentNode = currentNode.parentNode.orElse(null);
}
}
//Accept the command by applying() an Event
}
At some point, the parent needs to be instantiated to perform those checks. This could either be done by supplying the aggregate instance in the command (discouraged), or by supplying a Repository<Node>
and the nodeId
to the command handler, which is the aggregate itself and also discouraged. Currently I don't see a right way to do this and further down the road a way to test it.
unit-testing domain-driven-design aggregateroot axon
add a comment |
Suppose I have an aggregate that, for some operation, requires the existence of another aggregate. Let's assume I have a car
and a garage
. There might be a command called ParkInGarage
that looks like this:
public class ParkInGarage {
@TargetAggregateIdentifier
public final UUID carId;
public final Garage garage;
//... constructor omitted
}
I've read that to validate the existence of an aggregate, it is good practice to use the loaded aggregate in commands since that already implies its existence (as opposed to passing a garageId
).
Now when unit-testing the Car
using Axon's fixtures, I can not simply instantiate my Garage
by saying new Garage(buildGarageCmd)
. It will say:
java.lang.IllegalStateException: Cannot request current Scope if none is active
Because no infrastructure was set up.
How would I test such a case, or should I design the aggregate differently?
Abstracted, real-world example
The aggregate root I am working with may have a reference to itself to form a tree-structure of said aggregate root. Let's call it Node
.
@Aggregate
public class Node {
private Node parentNode;
}
Upon creation, I can pass an Optional<Node>
as parent, or set the parent at a later time using a separate command. Whether the parent should be defined as instance or by ID is part of the question.
public class AttachNodeCmd {
@TargetAggregateIdentifier
public final UUID nodeId;
public final Optional<Node> parentNode;
}
In the command handler, I need to check if attaching the node to given parent would introduce a cycle (the structure is supposed to be a tree, not a common graph).
@CommandHandler
public Node(AttachNodeCmd command) {
if (command.parentNode.isPresent()) {
Node currentNode = command.parentNode.get();
while (currentNode != null) {
if (currentNode.equals(this)) throw new RecursionException();
currentNode = currentNode.parentNode.orElse(null);
}
}
//Accept the command by applying() an Event
}
At some point, the parent needs to be instantiated to perform those checks. This could either be done by supplying the aggregate instance in the command (discouraged), or by supplying a Repository<Node>
and the nodeId
to the command handler, which is the aggregate itself and also discouraged. Currently I don't see a right way to do this and further down the road a way to test it.
unit-testing domain-driven-design aggregateroot axon
add a comment |
Suppose I have an aggregate that, for some operation, requires the existence of another aggregate. Let's assume I have a car
and a garage
. There might be a command called ParkInGarage
that looks like this:
public class ParkInGarage {
@TargetAggregateIdentifier
public final UUID carId;
public final Garage garage;
//... constructor omitted
}
I've read that to validate the existence of an aggregate, it is good practice to use the loaded aggregate in commands since that already implies its existence (as opposed to passing a garageId
).
Now when unit-testing the Car
using Axon's fixtures, I can not simply instantiate my Garage
by saying new Garage(buildGarageCmd)
. It will say:
java.lang.IllegalStateException: Cannot request current Scope if none is active
Because no infrastructure was set up.
How would I test such a case, or should I design the aggregate differently?
Abstracted, real-world example
The aggregate root I am working with may have a reference to itself to form a tree-structure of said aggregate root. Let's call it Node
.
@Aggregate
public class Node {
private Node parentNode;
}
Upon creation, I can pass an Optional<Node>
as parent, or set the parent at a later time using a separate command. Whether the parent should be defined as instance or by ID is part of the question.
public class AttachNodeCmd {
@TargetAggregateIdentifier
public final UUID nodeId;
public final Optional<Node> parentNode;
}
In the command handler, I need to check if attaching the node to given parent would introduce a cycle (the structure is supposed to be a tree, not a common graph).
@CommandHandler
public Node(AttachNodeCmd command) {
if (command.parentNode.isPresent()) {
Node currentNode = command.parentNode.get();
while (currentNode != null) {
if (currentNode.equals(this)) throw new RecursionException();
currentNode = currentNode.parentNode.orElse(null);
}
}
//Accept the command by applying() an Event
}
At some point, the parent needs to be instantiated to perform those checks. This could either be done by supplying the aggregate instance in the command (discouraged), or by supplying a Repository<Node>
and the nodeId
to the command handler, which is the aggregate itself and also discouraged. Currently I don't see a right way to do this and further down the road a way to test it.
unit-testing domain-driven-design aggregateroot axon
Suppose I have an aggregate that, for some operation, requires the existence of another aggregate. Let's assume I have a car
and a garage
. There might be a command called ParkInGarage
that looks like this:
public class ParkInGarage {
@TargetAggregateIdentifier
public final UUID carId;
public final Garage garage;
//... constructor omitted
}
I've read that to validate the existence of an aggregate, it is good practice to use the loaded aggregate in commands since that already implies its existence (as opposed to passing a garageId
).
Now when unit-testing the Car
using Axon's fixtures, I can not simply instantiate my Garage
by saying new Garage(buildGarageCmd)
. It will say:
java.lang.IllegalStateException: Cannot request current Scope if none is active
Because no infrastructure was set up.
How would I test such a case, or should I design the aggregate differently?
Abstracted, real-world example
The aggregate root I am working with may have a reference to itself to form a tree-structure of said aggregate root. Let's call it Node
.
@Aggregate
public class Node {
private Node parentNode;
}
Upon creation, I can pass an Optional<Node>
as parent, or set the parent at a later time using a separate command. Whether the parent should be defined as instance or by ID is part of the question.
public class AttachNodeCmd {
@TargetAggregateIdentifier
public final UUID nodeId;
public final Optional<Node> parentNode;
}
In the command handler, I need to check if attaching the node to given parent would introduce a cycle (the structure is supposed to be a tree, not a common graph).
@CommandHandler
public Node(AttachNodeCmd command) {
if (command.parentNode.isPresent()) {
Node currentNode = command.parentNode.get();
while (currentNode != null) {
if (currentNode.equals(this)) throw new RecursionException();
currentNode = currentNode.parentNode.orElse(null);
}
}
//Accept the command by applying() an Event
}
At some point, the parent needs to be instantiated to perform those checks. This could either be done by supplying the aggregate instance in the command (discouraged), or by supplying a Repository<Node>
and the nodeId
to the command handler, which is the aggregate itself and also discouraged. Currently I don't see a right way to do this and further down the road a way to test it.
unit-testing domain-driven-design aggregateroot axon
unit-testing domain-driven-design aggregateroot axon
edited Nov 16 '18 at 15:00
Double M
asked Nov 15 '18 at 15:02
Double MDouble M
743516
743516
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
I think @plalx is putting you on the right track. Commands are part of your API/Message Contract and exposing the Aggregate in there isn't that great an idea.
Additionally I'd like to note that the AggregateFixtures
in Axon are there to test a single Aggregate, not the coordination of operations between Aggregates.
Coordination between aggregates/bounded contexts is typically where you see sagas coming in to play. Now to be honest, I am a bit in doubt whether this use case justifies a Saga, but I could imagine that if the ParkCarInGarageCommand
fails because the Garage
Aggregate is full (for example), that you need to instruct the Car
Aggregate through another command telling it it's a no-go. The Saga set up in Axon might help you with this as you can easily catch (1) the exception from handling the command or (2) handle the event notifying the operation wasn't successful.
What aggregate would aParkCarInGarageCommand
be directed to? As far as I understand, sagas are only started by events. Thus something else will have to handle the command initially. How would that 'something else' get instances of whatever aggregates are required? Can you provide an example?
– Double M
Nov 16 '18 at 14:37
I have edited my post to provide a more concrete example of what I'm trying to do and test. It would be great if Axon could provide an example solution for this as currently I can't find any hint in the docs. I'm sure it is a common problem.
– Double M
Nov 16 '18 at 15:01
Also, if I can't have any aggregate(members) in commands or events, how do I reconstruct an aggregate root with object pointers to aggregate members with just the IDs? All these rules are incredibly restricting.
– Double M
Nov 16 '18 at 19:09
Any component/singleton/bean can have an@CommandHandler
annotation on it. So you could add a separate singleton dealing with theParkCarInGarageCommand
, which in turn sends commands, for example. If you'd want to use a Saga, then use, that should start on some events and in turn can publish commands to the Aggregates it is tied to. That would mean you'd have a different starting point of this operation, which I'd be hard pressed to tell you which it is as I am not familiar with your domain.
– Steven
Nov 19 '18 at 12:28
1
Thanks, I think I'm getting the hang of it. The solution to the tree 'consistency boundary' is to introduce another entity that acts as aggregate root and protects the tree structure invariant. All operations are performed through it, such as adding nodes and linking them. In the event (sourcing) handler for adding nodes, new nodes are being instantiated right there. This eliminates the need for a repository or existence check.
– Double M
Nov 19 '18 at 12:51
|
show 1 more comment
I wouldn't put AR instances in commands. Command schemas should be stable and easy to serialize/reserialize as they are message contracts.
What you could do instead is resolving the dependency in the command handler.
//ParkInGarage command handler
Garage garage = garageRepository.garageOfId(command.garageId);
Car car = carRepository.carOfId(command.carId);
car.parkIn(garage);
I don't know Axon Framework at all, but that should be relatively easy to test now.
That's a neat solution, however Axon doesn't let you inject repositories in command handlers and also discourages you from using repositories within aggregates, since loading takes time and increases the chances of concurrent modifications while the aggregate is locked. Your proposal makes a lot of sense, but I fear it's a more of a framework limitation in this case.
– Double M
Nov 16 '18 at 11:22
Seems like a weird framework limitation as resolving dependencies in command handlers/application services is an industry standard among DDD practitioners.
– plalx
Nov 16 '18 at 13:38
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53322271%2fhow-are-aggregates-instantiated-to-test-other-aggregates-with%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
I think @plalx is putting you on the right track. Commands are part of your API/Message Contract and exposing the Aggregate in there isn't that great an idea.
Additionally I'd like to note that the AggregateFixtures
in Axon are there to test a single Aggregate, not the coordination of operations between Aggregates.
Coordination between aggregates/bounded contexts is typically where you see sagas coming in to play. Now to be honest, I am a bit in doubt whether this use case justifies a Saga, but I could imagine that if the ParkCarInGarageCommand
fails because the Garage
Aggregate is full (for example), that you need to instruct the Car
Aggregate through another command telling it it's a no-go. The Saga set up in Axon might help you with this as you can easily catch (1) the exception from handling the command or (2) handle the event notifying the operation wasn't successful.
What aggregate would aParkCarInGarageCommand
be directed to? As far as I understand, sagas are only started by events. Thus something else will have to handle the command initially. How would that 'something else' get instances of whatever aggregates are required? Can you provide an example?
– Double M
Nov 16 '18 at 14:37
I have edited my post to provide a more concrete example of what I'm trying to do and test. It would be great if Axon could provide an example solution for this as currently I can't find any hint in the docs. I'm sure it is a common problem.
– Double M
Nov 16 '18 at 15:01
Also, if I can't have any aggregate(members) in commands or events, how do I reconstruct an aggregate root with object pointers to aggregate members with just the IDs? All these rules are incredibly restricting.
– Double M
Nov 16 '18 at 19:09
Any component/singleton/bean can have an@CommandHandler
annotation on it. So you could add a separate singleton dealing with theParkCarInGarageCommand
, which in turn sends commands, for example. If you'd want to use a Saga, then use, that should start on some events and in turn can publish commands to the Aggregates it is tied to. That would mean you'd have a different starting point of this operation, which I'd be hard pressed to tell you which it is as I am not familiar with your domain.
– Steven
Nov 19 '18 at 12:28
1
Thanks, I think I'm getting the hang of it. The solution to the tree 'consistency boundary' is to introduce another entity that acts as aggregate root and protects the tree structure invariant. All operations are performed through it, such as adding nodes and linking them. In the event (sourcing) handler for adding nodes, new nodes are being instantiated right there. This eliminates the need for a repository or existence check.
– Double M
Nov 19 '18 at 12:51
|
show 1 more comment
I think @plalx is putting you on the right track. Commands are part of your API/Message Contract and exposing the Aggregate in there isn't that great an idea.
Additionally I'd like to note that the AggregateFixtures
in Axon are there to test a single Aggregate, not the coordination of operations between Aggregates.
Coordination between aggregates/bounded contexts is typically where you see sagas coming in to play. Now to be honest, I am a bit in doubt whether this use case justifies a Saga, but I could imagine that if the ParkCarInGarageCommand
fails because the Garage
Aggregate is full (for example), that you need to instruct the Car
Aggregate through another command telling it it's a no-go. The Saga set up in Axon might help you with this as you can easily catch (1) the exception from handling the command or (2) handle the event notifying the operation wasn't successful.
What aggregate would aParkCarInGarageCommand
be directed to? As far as I understand, sagas are only started by events. Thus something else will have to handle the command initially. How would that 'something else' get instances of whatever aggregates are required? Can you provide an example?
– Double M
Nov 16 '18 at 14:37
I have edited my post to provide a more concrete example of what I'm trying to do and test. It would be great if Axon could provide an example solution for this as currently I can't find any hint in the docs. I'm sure it is a common problem.
– Double M
Nov 16 '18 at 15:01
Also, if I can't have any aggregate(members) in commands or events, how do I reconstruct an aggregate root with object pointers to aggregate members with just the IDs? All these rules are incredibly restricting.
– Double M
Nov 16 '18 at 19:09
Any component/singleton/bean can have an@CommandHandler
annotation on it. So you could add a separate singleton dealing with theParkCarInGarageCommand
, which in turn sends commands, for example. If you'd want to use a Saga, then use, that should start on some events and in turn can publish commands to the Aggregates it is tied to. That would mean you'd have a different starting point of this operation, which I'd be hard pressed to tell you which it is as I am not familiar with your domain.
– Steven
Nov 19 '18 at 12:28
1
Thanks, I think I'm getting the hang of it. The solution to the tree 'consistency boundary' is to introduce another entity that acts as aggregate root and protects the tree structure invariant. All operations are performed through it, such as adding nodes and linking them. In the event (sourcing) handler for adding nodes, new nodes are being instantiated right there. This eliminates the need for a repository or existence check.
– Double M
Nov 19 '18 at 12:51
|
show 1 more comment
I think @plalx is putting you on the right track. Commands are part of your API/Message Contract and exposing the Aggregate in there isn't that great an idea.
Additionally I'd like to note that the AggregateFixtures
in Axon are there to test a single Aggregate, not the coordination of operations between Aggregates.
Coordination between aggregates/bounded contexts is typically where you see sagas coming in to play. Now to be honest, I am a bit in doubt whether this use case justifies a Saga, but I could imagine that if the ParkCarInGarageCommand
fails because the Garage
Aggregate is full (for example), that you need to instruct the Car
Aggregate through another command telling it it's a no-go. The Saga set up in Axon might help you with this as you can easily catch (1) the exception from handling the command or (2) handle the event notifying the operation wasn't successful.
I think @plalx is putting you on the right track. Commands are part of your API/Message Contract and exposing the Aggregate in there isn't that great an idea.
Additionally I'd like to note that the AggregateFixtures
in Axon are there to test a single Aggregate, not the coordination of operations between Aggregates.
Coordination between aggregates/bounded contexts is typically where you see sagas coming in to play. Now to be honest, I am a bit in doubt whether this use case justifies a Saga, but I could imagine that if the ParkCarInGarageCommand
fails because the Garage
Aggregate is full (for example), that you need to instruct the Car
Aggregate through another command telling it it's a no-go. The Saga set up in Axon might help you with this as you can easily catch (1) the exception from handling the command or (2) handle the event notifying the operation wasn't successful.
answered Nov 16 '18 at 12:36
StevenSteven
1,32988
1,32988
What aggregate would aParkCarInGarageCommand
be directed to? As far as I understand, sagas are only started by events. Thus something else will have to handle the command initially. How would that 'something else' get instances of whatever aggregates are required? Can you provide an example?
– Double M
Nov 16 '18 at 14:37
I have edited my post to provide a more concrete example of what I'm trying to do and test. It would be great if Axon could provide an example solution for this as currently I can't find any hint in the docs. I'm sure it is a common problem.
– Double M
Nov 16 '18 at 15:01
Also, if I can't have any aggregate(members) in commands or events, how do I reconstruct an aggregate root with object pointers to aggregate members with just the IDs? All these rules are incredibly restricting.
– Double M
Nov 16 '18 at 19:09
Any component/singleton/bean can have an@CommandHandler
annotation on it. So you could add a separate singleton dealing with theParkCarInGarageCommand
, which in turn sends commands, for example. If you'd want to use a Saga, then use, that should start on some events and in turn can publish commands to the Aggregates it is tied to. That would mean you'd have a different starting point of this operation, which I'd be hard pressed to tell you which it is as I am not familiar with your domain.
– Steven
Nov 19 '18 at 12:28
1
Thanks, I think I'm getting the hang of it. The solution to the tree 'consistency boundary' is to introduce another entity that acts as aggregate root and protects the tree structure invariant. All operations are performed through it, such as adding nodes and linking them. In the event (sourcing) handler for adding nodes, new nodes are being instantiated right there. This eliminates the need for a repository or existence check.
– Double M
Nov 19 '18 at 12:51
|
show 1 more comment
What aggregate would aParkCarInGarageCommand
be directed to? As far as I understand, sagas are only started by events. Thus something else will have to handle the command initially. How would that 'something else' get instances of whatever aggregates are required? Can you provide an example?
– Double M
Nov 16 '18 at 14:37
I have edited my post to provide a more concrete example of what I'm trying to do and test. It would be great if Axon could provide an example solution for this as currently I can't find any hint in the docs. I'm sure it is a common problem.
– Double M
Nov 16 '18 at 15:01
Also, if I can't have any aggregate(members) in commands or events, how do I reconstruct an aggregate root with object pointers to aggregate members with just the IDs? All these rules are incredibly restricting.
– Double M
Nov 16 '18 at 19:09
Any component/singleton/bean can have an@CommandHandler
annotation on it. So you could add a separate singleton dealing with theParkCarInGarageCommand
, which in turn sends commands, for example. If you'd want to use a Saga, then use, that should start on some events and in turn can publish commands to the Aggregates it is tied to. That would mean you'd have a different starting point of this operation, which I'd be hard pressed to tell you which it is as I am not familiar with your domain.
– Steven
Nov 19 '18 at 12:28
1
Thanks, I think I'm getting the hang of it. The solution to the tree 'consistency boundary' is to introduce another entity that acts as aggregate root and protects the tree structure invariant. All operations are performed through it, such as adding nodes and linking them. In the event (sourcing) handler for adding nodes, new nodes are being instantiated right there. This eliminates the need for a repository or existence check.
– Double M
Nov 19 '18 at 12:51
What aggregate would a
ParkCarInGarageCommand
be directed to? As far as I understand, sagas are only started by events. Thus something else will have to handle the command initially. How would that 'something else' get instances of whatever aggregates are required? Can you provide an example?– Double M
Nov 16 '18 at 14:37
What aggregate would a
ParkCarInGarageCommand
be directed to? As far as I understand, sagas are only started by events. Thus something else will have to handle the command initially. How would that 'something else' get instances of whatever aggregates are required? Can you provide an example?– Double M
Nov 16 '18 at 14:37
I have edited my post to provide a more concrete example of what I'm trying to do and test. It would be great if Axon could provide an example solution for this as currently I can't find any hint in the docs. I'm sure it is a common problem.
– Double M
Nov 16 '18 at 15:01
I have edited my post to provide a more concrete example of what I'm trying to do and test. It would be great if Axon could provide an example solution for this as currently I can't find any hint in the docs. I'm sure it is a common problem.
– Double M
Nov 16 '18 at 15:01
Also, if I can't have any aggregate(members) in commands or events, how do I reconstruct an aggregate root with object pointers to aggregate members with just the IDs? All these rules are incredibly restricting.
– Double M
Nov 16 '18 at 19:09
Also, if I can't have any aggregate(members) in commands or events, how do I reconstruct an aggregate root with object pointers to aggregate members with just the IDs? All these rules are incredibly restricting.
– Double M
Nov 16 '18 at 19:09
Any component/singleton/bean can have an
@CommandHandler
annotation on it. So you could add a separate singleton dealing with the ParkCarInGarageCommand
, which in turn sends commands, for example. If you'd want to use a Saga, then use, that should start on some events and in turn can publish commands to the Aggregates it is tied to. That would mean you'd have a different starting point of this operation, which I'd be hard pressed to tell you which it is as I am not familiar with your domain.– Steven
Nov 19 '18 at 12:28
Any component/singleton/bean can have an
@CommandHandler
annotation on it. So you could add a separate singleton dealing with the ParkCarInGarageCommand
, which in turn sends commands, for example. If you'd want to use a Saga, then use, that should start on some events and in turn can publish commands to the Aggregates it is tied to. That would mean you'd have a different starting point of this operation, which I'd be hard pressed to tell you which it is as I am not familiar with your domain.– Steven
Nov 19 '18 at 12:28
1
1
Thanks, I think I'm getting the hang of it. The solution to the tree 'consistency boundary' is to introduce another entity that acts as aggregate root and protects the tree structure invariant. All operations are performed through it, such as adding nodes and linking them. In the event (sourcing) handler for adding nodes, new nodes are being instantiated right there. This eliminates the need for a repository or existence check.
– Double M
Nov 19 '18 at 12:51
Thanks, I think I'm getting the hang of it. The solution to the tree 'consistency boundary' is to introduce another entity that acts as aggregate root and protects the tree structure invariant. All operations are performed through it, such as adding nodes and linking them. In the event (sourcing) handler for adding nodes, new nodes are being instantiated right there. This eliminates the need for a repository or existence check.
– Double M
Nov 19 '18 at 12:51
|
show 1 more comment
I wouldn't put AR instances in commands. Command schemas should be stable and easy to serialize/reserialize as they are message contracts.
What you could do instead is resolving the dependency in the command handler.
//ParkInGarage command handler
Garage garage = garageRepository.garageOfId(command.garageId);
Car car = carRepository.carOfId(command.carId);
car.parkIn(garage);
I don't know Axon Framework at all, but that should be relatively easy to test now.
That's a neat solution, however Axon doesn't let you inject repositories in command handlers and also discourages you from using repositories within aggregates, since loading takes time and increases the chances of concurrent modifications while the aggregate is locked. Your proposal makes a lot of sense, but I fear it's a more of a framework limitation in this case.
– Double M
Nov 16 '18 at 11:22
Seems like a weird framework limitation as resolving dependencies in command handlers/application services is an industry standard among DDD practitioners.
– plalx
Nov 16 '18 at 13:38
add a comment |
I wouldn't put AR instances in commands. Command schemas should be stable and easy to serialize/reserialize as they are message contracts.
What you could do instead is resolving the dependency in the command handler.
//ParkInGarage command handler
Garage garage = garageRepository.garageOfId(command.garageId);
Car car = carRepository.carOfId(command.carId);
car.parkIn(garage);
I don't know Axon Framework at all, but that should be relatively easy to test now.
That's a neat solution, however Axon doesn't let you inject repositories in command handlers and also discourages you from using repositories within aggregates, since loading takes time and increases the chances of concurrent modifications while the aggregate is locked. Your proposal makes a lot of sense, but I fear it's a more of a framework limitation in this case.
– Double M
Nov 16 '18 at 11:22
Seems like a weird framework limitation as resolving dependencies in command handlers/application services is an industry standard among DDD practitioners.
– plalx
Nov 16 '18 at 13:38
add a comment |
I wouldn't put AR instances in commands. Command schemas should be stable and easy to serialize/reserialize as they are message contracts.
What you could do instead is resolving the dependency in the command handler.
//ParkInGarage command handler
Garage garage = garageRepository.garageOfId(command.garageId);
Car car = carRepository.carOfId(command.carId);
car.parkIn(garage);
I don't know Axon Framework at all, but that should be relatively easy to test now.
I wouldn't put AR instances in commands. Command schemas should be stable and easy to serialize/reserialize as they are message contracts.
What you could do instead is resolving the dependency in the command handler.
//ParkInGarage command handler
Garage garage = garageRepository.garageOfId(command.garageId);
Car car = carRepository.carOfId(command.carId);
car.parkIn(garage);
I don't know Axon Framework at all, but that should be relatively easy to test now.
answered Nov 15 '18 at 16:21
plalxplalx
33.1k44770
33.1k44770
That's a neat solution, however Axon doesn't let you inject repositories in command handlers and also discourages you from using repositories within aggregates, since loading takes time and increases the chances of concurrent modifications while the aggregate is locked. Your proposal makes a lot of sense, but I fear it's a more of a framework limitation in this case.
– Double M
Nov 16 '18 at 11:22
Seems like a weird framework limitation as resolving dependencies in command handlers/application services is an industry standard among DDD practitioners.
– plalx
Nov 16 '18 at 13:38
add a comment |
That's a neat solution, however Axon doesn't let you inject repositories in command handlers and also discourages you from using repositories within aggregates, since loading takes time and increases the chances of concurrent modifications while the aggregate is locked. Your proposal makes a lot of sense, but I fear it's a more of a framework limitation in this case.
– Double M
Nov 16 '18 at 11:22
Seems like a weird framework limitation as resolving dependencies in command handlers/application services is an industry standard among DDD practitioners.
– plalx
Nov 16 '18 at 13:38
That's a neat solution, however Axon doesn't let you inject repositories in command handlers and also discourages you from using repositories within aggregates, since loading takes time and increases the chances of concurrent modifications while the aggregate is locked. Your proposal makes a lot of sense, but I fear it's a more of a framework limitation in this case.
– Double M
Nov 16 '18 at 11:22
That's a neat solution, however Axon doesn't let you inject repositories in command handlers and also discourages you from using repositories within aggregates, since loading takes time and increases the chances of concurrent modifications while the aggregate is locked. Your proposal makes a lot of sense, but I fear it's a more of a framework limitation in this case.
– Double M
Nov 16 '18 at 11:22
Seems like a weird framework limitation as resolving dependencies in command handlers/application services is an industry standard among DDD practitioners.
– plalx
Nov 16 '18 at 13:38
Seems like a weird framework limitation as resolving dependencies in command handlers/application services is an industry standard among DDD practitioners.
– plalx
Nov 16 '18 at 13:38
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53322271%2fhow-are-aggregates-instantiated-to-test-other-aggregates-with%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown