How to a raise a domain event for the entity when the entity is created in clean architecture - clean-architecture

I have a project created using the clean architecture template.
If I want a domain event be raised when a new project is created, where do I add that?
If I have to raise an event whenever a new item be added to a project, I can accomplish that in the Project entity as shown here.
Similarly for MarkCompletion of a ToDoItem as done here.
But its not clear where do I put the code to raise an event when a new Project is created?
One option is doing something like the following in Create End Point here.
newProject.Events.Add(new ProjectCreatedEvent(newProject));
But this is in UI, away from the domain model, and so does not feel right.
The other option is using ef core interceptors. So when ever save changes is called, just raise event as appropriate something like here.
And if I add event in Project ctor, then this is triggered even in case of an update.
public Project(string name)
{
Name = Guard.Against.NullOrEmpty(name, nameof(name));
var newProjectCreatedEvent = new NewProjectCreatedEvent(this);
Events.Add(newProjectCreatedEvent);
}
Are there any better options/patterns?
Any pointer is deeply appreciated.

When you need to raise a domain event on project creation I would create a factory method that publishes the event.
You can use a static method or implement a factory object.
public class Project : BaseEntity, IAggregateRoot
{
public static Project newProject(string name)
{
var project = new Project(name);
var newProjectCreatedEvent = new NewProjectCreatedEvent(project);
Events.Add(newProjectCreatedEvent);
return project;
}
private Project(string name)
{
Name = Guard.Against.NullOrEmpty(name, nameof(name));
}
}

Related

ArrayListModel will not sync with JList

I have combed through SO, and have found many questions on the topic of my problem but do not answer it.
I am setting up an MVC, I have set up things correctly to best of my knowledge but I cannot get the Controller to show in my view. I am working on an assignment that essentially is a program for a Video Rental Store.
First, In a class called RentalStoreGUI, I set up my panels and everything looks good when I run.
RentalStoreEngine model = new RentalStoreEngine();
JList<DVD> list = new JList<DVD>();
list.setModel(model);
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
list.setVisible(true);
list.setSelectedIndex(0);
jScrollPane = new JScrollPane(list);
add(jScrollPane, BorderLayout.CENTER);
add(buttonPanel, BorderLayout.SOUTH);
As you can see I set my model for the list based on another class called RentalStoreEngine() and it implements AbstractListModel. The Abstract List model is functioning when I do class specific testing and all of the necessary methods are implemented. Here is an example of my add method from that class:
public void add(DVD d){
if (d != null){
rentals.add(d);//rentals is an arrayList<DVD> instantiated earlier
fireIntervalAdded(this, rentals.size() - 1, rentals.size() - 1);
}
}
Here is the actionPerformed method, it runs DVD_Dialog which simply gets some input from the user and creates a new DVD object from that.
public void actionPerformed(ActionEvent event) {
if(event.getSource() == rentDVD){
DVD_Dialog = new RentDVDDialog(this, null);
DVD_Dialog.clear();
DVD_Dialog.setVisible(true);
dvd = new DVD(DVD_Dialog.getTitleText(),DVD_Dialog.getRenterText(),
DVD_Dialog.getRentedOnText(), DVD_Dialog.getDueBackText());
if(DVD_Dialog.closeStatus() == true){
model.add(dvd);
}
}
Eclipse gives me no errors, until I run it. I then receive a nullPointerException at the line model.add(dvd); Based on all my research the list.setModel(model) and the fireIntervalAdded method line should update the Jlist on its own. But it does not. And as I said, class specific testing for both the GUI and the Model are producing the desired results, but when it comes to integrating them I am at a loss.

grails 2.2.2 platform-core-plugin No signature of method event in domain model

I try out the platform-core-1.0 rc5 Plugin to services by events. Now I write a service in the grails-plugin "listadmin":
package listadmin
class SECO_ListenService {
#grails.events.Listener(topic='getEntriesOfList', namespace='listadmin')
def getEntriesOfList(String intnalListName) {
println "SECO_ListenService"
def Liste aList = Liste.findByInternal_name(intnalListName)
return aList.eintrage.toList()
}
}
This service should return a list for dropdown in an other grails-plugin called "institutionadmin". I want to use this list of the service for a dropdown of a domain-model. I should mention that I use dynamic scaffolding. Now I try to call this event in the domain-model:
package institutionadmin
import org.springframework.dao.DataIntegrityViolationException
class Einrichtung {
Long einrichtungs_type
Long type_of_conzept
int anzahl_gruppen
int anzahl_kinder_pro_Gruppe
String offnungszeiten
static hasMany = [rooms : Raum]
static constraints = {
def aList = []
def reply = event(for:"listadmin", topic:"getEntriesOfList", data:"einrichtung_type").waitFor()
aList = reply.value.toList()
einrichtungs_type(inList: aList)
}
}
If I try to run this application i get the following error:
Caused by MissingMethodException: No signature of method: institutionadmin.Einrichtung.event() is applicable for argument types: (java.util.LinkedHashMap) values: [[for:listadmin, topic:testEventBus]]
Possible solutions: ident(), every(), every(groovy.lang.Closure), count(), get(java.io.Serializable), print(java.lang.Object)
If call this event in a controller everything is fine and the documentation of this plugin describe that I can call events also in domain-models and services... This error-method tell me, that the class don't know the event method.
Do I have to configure anything else?
Should call the event in another way or where is my mistake?
Has anybody experiences with this module?
The event(...) dynamic methods are not available on class (static) level.
You can pull the grailsEvents spring bean and call its event() method alternatively. You still have to get the bean from the application context statically though.
You could also use a custom validator instead, as you can get the current domain instance as a parameter, which should have the event() method injected.
something like this :
static myList = []
static constraints = {
einrichtungs_type validator: { value, instance ->
if(!myList){
// cache it the first time you save/validate the domain
// I would probably recommend you NOT to do this here though in
// real life scenario
def reply = instance.event('blabla').get()
myList = reply.value.toList()
}
return value in myList
}
}
Anyway, In my case I would probably load the list elsewhere (in the Bootstrap.groovy for instance) and use it / inject it in my domain instead of doing in the constraints closure.
I faced similar kind of problem, I wanted to use the event call inside a service class which is going to call the listener in other service class. When I started my application I got the same error.What I did was, added the plugin(platform-core:1.0.RC5) entries in BuildConfig.groovy like below
plugins {
build(":tomcat:$grailsVersion",
":platform-core:1.0.RC5") {
export = false
}
compile ':platform-core:1.0.RC5'
runtime ':platform-core:1.0.RC5'
}
Then I ran grails > clean and grails > compile on that project and restarted the server.It started working. Might be you can give a try.

Entity Framework 4.3.1 add-migration error: "model backing the context has changed"

I'm getting an error when trying to run the EF 4.3.1 add-migrations command:
"The model backing the ... context has changed since the database was created".
Here's one sequence that gets the error (although I've tried probably a dozen variants which also all fail)...
1) Start with a database that was created by EF Code First (ie, already contains a _MigrationHistory table with only the InitialCreate row).
2) The app's code data model and database are in-sync at this point (the database was created by CF when the app was started).
3) Because I have four DBContexts in my "Services" project, I didn't run 'enable-migrations' command (it doesn't handle multipe contexts). Instead, I manually created the Migrations folder in the Services project and the Configuration.cs file (included at end of this post). [I think I read this in a post somewhere]
4) With the database not yet changed, and the app stopped, I use the VS EDM editor to make a trivial change to my data model (add one property to an existing entity), and have it generate the new classes (but not modify the database, obviously). I then rebuild the solution and all looks OK (but don't delete the database or restart the app, of course).
5) I run the following PMC command (where "App" is the name of one of the classes in Configuration.cs):
PM> add-migration App_AddTrivial -conf App -project Services -startup Services -verbose
... which fails with the "The model ... has changed. Consider using Code First Migrations..." error.
What am I doing wrong? And does anyone else see the irony in the tool telling me to use what I'm already trying to use ;-)
What are the correct steps for setting-up a solution starting with a database that was created by EF CF? I've seen posts saying to run an initial migration with -ignorechanges, but I've tried that and it doesn't help. Actually, I've spent all DAY testing various permutations, and nothing works!
I must be doing something really stupid, but I don't know what!
Thanks,
DadCat
Configuration.cs:
namespace mynamespace
{
internal sealed class App : DbMigrationsConfiguration
{
public App()
{
AutomaticMigrationsEnabled = false;
MigrationsNamespace = "Services.App.Repository.Migrations";
}
protected override void Seed(.Services.App.Repository.ModelContainer context)
{
}
}
internal sealed class Catalog : DbMigrationsConfiguration<Services.Catalog.Repository.ModelContainer>
{
public Catalog()
{
AutomaticMigrationsEnabled = false;
MigrationsNamespace = "Services.Catalog.Repository.Migrations";
}
protected override void Seed(Services.Catalog.Repository.ModelContainer context)
{
}
}
internal sealed class Portfolio : DbMigrationsConfiguration<Services.PortfolioManagement.Repository.ModelContainer>
{
public Portfolio()
{
AutomaticMigrationsEnabled = false;
MigrationsNamespace = "Services.PortfolioManagement.Repository.Migrations";
}
protected override void Seed(Services.PortfolioManagement.Repository.ModelContainer context)
{
}
}
internal sealed class Scheduler : DbMigrationsConfiguration<.Services.Scheduler.Repository.ModelContainer>
{
public Scheduler()
{
AutomaticMigrationsEnabled = false;
MigrationsNamespace = "Services.Scheduler.Repository.Migrations";
}
protected override void Seed(Services.Scheduler.Repository.ModelContainer context)
{
}
}
}
When using EF Migrations you should have one data context per database. I know that it can grow really large, but by trying to split it you will run into several problems. One is the migration issue that you are experiencing. Later on you will probably be facing problems when trying to make queries joining tables from the different contexts. Don't go that way, it's against how EF is designed.

EF Object entity State moves to Unchanged when attached to new Context

I have go the oddest problem, I get an object from EF and pass it back to the Business Logic for manipulation, when finished i'm trying to save the object back to the DB, when the object is passed into the following method it's EntityState is Modified but as soon as the attach line of code is run it is set to UnChanged hence the Save will not work.
Does anyone know why EF would do this?
public void Save(IEntity entity)
{
using (var context = new eDocumentEntities())
{
using (var scope = new TransactionScope())
{
if (entity.Id != 0)
context.AttachTo(entity.EntitySet, entity);
else
context.AddObject(entity.EntitySet, entity);
context.SaveChanges();
scope.Complete();
}
}
}
Since entity change tracking is encapsulated in Context, naturally the entity loses state and other tracking stuff when it gets detached from context.
Ok I found the solution to the problem here but Ii'm more interested in an explanation, why would EF do this, seems very counter productive!?
http://geekswithblogs.net/michelotti/archive/2009/11/27/attaching-modified-entities-in-ef-4.aspx

Entity Framework Designer Extension Not loading

I created a small extension for the EF designer that adds a new property to the property window. I did this using a vsix project (new project -> c# -> extensibility -> vsix project). When I hit F5 the experimental VS instance starts up. I create a new project, add an entity data model and add an entity. However, my break points never get hit and I don't see the property. Any ideas as to what I might be doing wrong?
public class AggregateRootValue
{
internal static XName AggregateRootElementName = XName.Get("AggregateRoot", "http://efex");
private readonly XElement _property;
private readonly PropertyExtensionContext _context;
public AggregateRootValue(XElement parent, PropertyExtensionContext context)
{
_property = parent;
_context = context;
}
[DisplayName("Aggregate Root")]
[Description("Determines if an entity is an Aggregate Root")]
[Category("Extensions")]
[DefaultValue(true)]
public string AggregateRoot
{
get
{
XElement child = _property.Element(AggregateRootElementName);
return (child == null) ? bool.TrueString : child.Value;
}
set
{
using (EntityDesignerChangeScope scope = _context.CreateChangeScope("Set AggregateRoot"))
{
var element = _property.Element(AggregateRootElementName);
if (element == null)
_property.Add(new XElement(AggregateRootElementName, value));
else
element.SetValue(value);
scope.Complete();
}
}
}
}
[Export(typeof(IEntityDesignerExtendedProperty))]
[EntityDesignerExtendedProperty(EntityDesignerSelection.ConceptualModelEntityType)]
public class AggregateRootFactory : IEntityDesignerExtendedProperty
{
public object CreateProperty(XElement element, PropertyExtensionContext context)
{
var edmXName = XName.Get("Key", "http://schemas.microsoft.com/ado/2008/09/edm");
var keys = element.Parent.Element(edmXName).Elements().Select(e => e.Attribute("Name").Value);
if (keys.Contains(element.Attribute("Name").Value))
return new AggregateRootValue(element, context);
return null;
}
}
EDIT: I put the code on Github: https://github.com/devlife/Sandbox
EDIT: After Adding the MEF component to the manifest as suggested, the extension still never loads. Here is a picture of the manifest:
So the answer, as it turns out, is in how I setup my project. I put both classes inside the project which produces the VSIX file. By simply moving those classes into another project and setting that project as the MEF Component in the manifest (and thus copying the assembly) it worked like a charm!
For VS2012, it is only needed to add Solution as MEF component also. Just add whole solution as MEF component also.
Then it works surprisingly fine.
It seems the dll built by your project isn't automatically included in the generated VSIX package, and VS2013 doesn't give you options through the IDE to change this (that I can work out, anyway).
You have to manually open the project file and alter the XML. The property to change is IncludeAssemblyInVSIXContainer.
Seen here: How to include VSIX output in it's package?

Resources