Currently I am learning Domain Driven Design. Based on my understanding I have created a sample application which does some operations on country.
I have crated a class library named "MyTest.Country" which contains all commands-
--MyTest.Country (ProjectName)
-- Commands (Folder)
--CreateCountry (: ICommand)
--DeleteCountry (: ICommand)
I have another class library named "MyTest.CountryClient" which interacts with the database using EF.
--MyTest.CountryClient (Project)
--CountryClass (ClassFile)
--CreateCountry (Method)
--DeleteCountry (Method)
--GetAllCountryList (Method)
Yet another classlibrary for services named "MyTest.CountryServices" which contains the handler.
--MyTest.CountryServices (Project)
--CountryHandler : IHandleMessages<CreateCountry>
: IHandleMessages<DeleteCountry>
I have a web API which sends command to "MyTest.CountryServices" using NServiceBus for creating or Deleting the country. The message is handled by CountryHandler and then it invokes the respective method from "MyTestCountryClient".
I know that Country is an entity and cannot be defined as a domain. However, I am only trying to implement the DDD.
My question here is -
Am I following the proper DDD principles here?
If I want to get all country list, should I directly call MyTest.CountryClient? or I need to call services first even for the fetching operation?
In your case the CountryClient seems to be your Repository. If so, yes you can call it directly.
I suggest you start into DDD with the building blocks. And do not dig into Messages and Commands in the beggining.
Related
On some of my projects, I use the double dispatch mechanism to provide at run time a "view" of my infrastructure module to my domain module (Strengthening your domain: The double dispatch pattern). What I call 'modules' above is simply separate jar files where the dependency from service.jar->domain.jar is enforced at compile time only. Will I be able to have this working on java-9 if I define my service and domain as 'true' java 9 modules?
module domain
L Fee.java
L Payment recordPayment(double, BalanceCalculator)
L BalanceCalculator.java
module service
L BalanceCalculatorImpl.java // implements BalanceCalculator
L double calculate(Fee fee) //call fee.recordPayment(amount,this)
Yes that is possible. Here are some things to consider:
The module domain needs to export the package containing Fee. Possibly to everyone but at least to service.
The module service will have to require domain as BalanceCalculatorImpl has to access BalanceCalculator since it implements it.
It looks like clients of service need to know about domain as well, which is a textbook case for implied readability.
In a simple setup either service or some third module will have to instantiate BalanceCalculatorImpl and pass it to Fee, this can not happen in domain or it would create a cyclic dependency.
A more advanced solution would be services, where all code that can access BalanceCalculator, even inside domain, can get hold of all its implementations.
Taking all of these into account, this is what the two module declarations might look like:
module com.example.domain {
// likely some requires clauses
// export packages containing Fee and BalanceCalculator
exports com.example.domain.fee;
exports com.example.domain.balance;
}
module com.example.service {
requires public com.example.domain;
// likely some more requires clauses
// expose BalanceCalculatorImpl as a service,
// which makes it unnecessary to export the containing package
provides com.example.domain.balance.BalanceCalculator
with com.example.service.balance.BalanceCalculatorImpl;
}
Then every module that likes to use BalanceCalculator can declare it in its module declaration with uses com.example.domain.balance.BalanceCalculator and get instances of that using Java's ServiceLoader.
You can find more practical applications of the module system (particularly for services] in a demo I created.
(Note: The answer was revised after this exchange.)
Suppose that I have 2 aggregate roots (AR) in my domain and invoking some method on the 1st requires access to an instance of the 2nd. In DDD how and where should retrieval and creation of the 2nd AR happen?
Here's a contrived example TravelerEntity that needs access to a SuitcaseEntity. I'm looking for an answer that doesn't pollute the domain layer with infrastructure code.
public class TravelerEntity {
// null if traveler has no suitcase yet.
private String suitcaseId = ...;
...
// Returns an empty suitcase ready for packing. Caller
public SuitcaseEntity startTrip(SuitcaseRepository repo) {
SuitcaseEntity suitcase;
if (suitcaseId == null) {
suitcase = new SuitcaseFactory().create();
suitcase = repo.save(suitcase);
suitcaseId = suitcase.getId();
} else {
suitcase = repo.findOne(suitcaseId);
}
suitcase.emptyContents();
return suitcase;
}
}
An application layer service handling the start trip request would get the appropriate SuitcaseRepository implementation via DI, get the TravelerEntity via a TravelerRepository implementation and call its startTrip() method.
The only alternative I thought of was to move SuitcaseEntity management to a domain service, but I don't want to create the suitcase before starting the trip, and I don't want to end up with an anemic TravelerEntity.
I'm a little uncertain about one AR creating and saving another AR. Is this OK since the repo and factory encapsulate specifics about the 2nd AR? Is there a danger I'm missing? Is there a better alternative?
I'm new enough to DDD to question my thinking on this. And the other questions I found about ARs seem to focus on identifying them properly, not on managing their lifecycles in relation to one another.
Ideally TravelerEntity wouldn't manipulate a SuitcaseRepository because it shouldn't know about an external thing where suitcases are stored, only about its own internals. Instead, it could new up a SuitCase and add it to its internal [list of] suitcases. If you wanted that to work with ORMs without specifically adding the suitcase to the repository though, you'd have to store the whole suitcase object in TravelerEntity.suitcaseList and not just its ID, which conflicts with the "store references to other AR's as IDs" best practice.
Moreover, TravelerEntity.startTrip() returning a suitcase seems a bit artificial and unexplicit and you'll be in trouble if you need to return other entities created by startTrip(). So a good solution could be to have TravelerEntity emit a SuitcaseAdded event with the suitcase data in it once it has added the suitcase to its list. An application service could subscribe to the event, add the suitcase to SuitcaseRepository and commit the transaction, effectively saving both the new suitcase and the modified traveler to the database.
Alternatively, you could place startTrip() in a Domain Service instead of an Entity. There it might be more legit to use SuitcaseRepository since a domain service is allowed know about multiple domain entities and the overall domain process going on.
First of all persistence is not domain's job so i would get rid of all the repositories from the domain models and create a service that would use them.
Second of all you should rethink your design. Why a StartTrip method of a Traveller should return a SuitCase?
A Traveller either has or hasn't a suitcase. Once you have retrieved the Traveller you should already have their SuitCases too.
public class StartTripService {
public void StartTrip(int travellerId) {
var traveller = travellerRepo.Get(travellerId);
traveller.StartTrip();
}
}
I'm struggling a bit with some of the base concepts of U2 Toolkit (and I've been quite successful with the previous version!).
First, I had to add using U2.Data.Client.UO; in order to reference UniSession or UniFile. This may just be general ignorance, but doesn't 'using U2.Data.Client' imply that I also want the .UO stuff under it?!?
Second - what (conceptually) are the differences between connecting via U2Connection's Open(), or UniSession's OpenSession()? Do each of them provide a different context in which to work?
Finally - while the examples provided in the doc and in Rajan's various articles are helpful, I'd like something a little more practical: how about a simple "here's how you read and write specific records in a Unidata file"?
Thanks!
Please see answer for the first and second questions
Regarding Namespace
If you want to develop application using ADO.NET ( SQL Access, UCI SERVER), you need one namespace (U2.Data.Client )
If you want to develop application using UO.NET ( Native Access, UO SERVER), you need two namespaces (U2.Data.Client and U2.Data.Client.UO)
U2.Data.Client namespace generally have Microsoft ADO.NET Specification Classes.
U2.Data.Client.UO namespace generally have UniObjects Native Specification Classes. As you have used in the past UODOTNET.DLL, you can feel all the Classes are there.
Regarding U2Connection/UniSession
This is by Design.
U2Connection.Open() calls UniSession.Open() when you use Accessmode=’Native’ in Connection String. You can verify from the LOG/TRACE File. In this case, basically, U2Connection and U2Session are same. U2Connection Class just passes connection string to UniSession Class and then UniSession Class uses this connection string and calls Open(). This is an improvement from the old way where you have used Static Class UniObjects(…) and there was no concept of standard connection string. Basically we replace Static Class UniObjects(…) to U2Connection Class and provided connection string capabilities.
U2Connection.Open() calls UCINET.Open() when you use Accessmode=’SQL’ in Connection String. You can verify from the LOG/TRACE File.
Is this clear()?
In Mojito on top of Node.js, I followed the example on http://developer.yahoo.com/cocktails/mojito/docs/quickstart/
What I did was renaming controller.server.js to controller.server-foo.js, and created a new file controller.server.js to show "Hello World".
But when mojito is started, the old file controller.server-foo.js is being used and so the "Hello World" is not printed. How come Mojito will use the old file?
(I also tried renaming controller.server-foo.js to foo-controller.server.js and now the "Hello World" is printed, but why is controller.server-foo.js used?)
I found out that historically, the "affinity" of the controller can be two parts. The first part is common, server, or client, and the second part is optional, and it might be tests, or other words, so use other names such as controller-not-used-server.js to disable it.
#Charles, there are 3 registration processes in mojito (yes, it is confusing at first):
Affinity (server, client or common).
YUI.add when creating yui modules (controllers, models, binders, etc)
and the less common which is the registration by name (which includes soemthing that we call selectors)
In your case, by having two controllers, one of them with a custom selector named "foo", you are effectible putting in use the 3 registration at once. Here is what happen internally:
A controller is always detonated as "controller" filename from the mojit folder, which is part of the registration by name, and since you have "foo" selector for one of the controller, your mojit will have to modes, "default" and "foo". Which one of them will be use? depends on the application.json, where you can have some conditions to set the value of "selector", which by default is empty. If you set the value of selector to "foo" when, for example, device is an iphone, then that controller will be used when that condition matches.
Then the YUI.add plays an important role, it is the way we can identify which controller should be used, and its only requirement is that NO OTHER MODULE in the app can have the same YUI Module name, which means that your controllers can't be named the same when registering them thru YUI.add. And I'm sure this is what is happening in your case. If they both have the same name under YUI.add() one will always override the other, and you should probably see that in the logs as a warning, if not, feel free to open an issue thru github.
To summarize:
The names used when registering YUI modules have to be unique, in your case, you can use: YUI.add('MyMojit', function(){}) and YUI.add('MyMojitFoo', function(){}), for each controller.
Use the selector (e.g.: controller.server-mobile.js) to select which YUI module should be used for a particular request by setting selector to the proper value in application.json.
I have an EDMX model with a generated context.
Now i generated a Self Tracking Entities library is separate project and referenced this from the EDMX model.
Also set the correct namespace in the context to the same namespace as the entities.
Now working with this all works except when i try to create a WCF data service with this context.
So just create new ObjectContext and working with it directly works fine.
But having referenced the context + model lib and the entities lib i get the following error when loading the service
The server encountered an error processing the request. The exception message is 'Value cannot be null. Parameter name: key'. See server logs for more details. The exception stack trace is:
Now i found that this could happen when using data service with external entity lib and fix was overriding the createcontext
with code
Collapse
System.Data.Metadata.Edm.ItemCollection itemCollection;
if (!context.MetadataWorkspace.TryGetItemCollection
(System.Data.Metadata.Edm.DataSpace.CSSpace, out itemCollection))
{
var tracestring = context.CreateQuery<ClientDataStoreContainer>("ClientDataStoreContainer.DataSet").ToTraceString();
}
return context;
Now the error is gone but i get the next one and that is:
Object mapping could not be found for Type with identity 'ClientDataStoreEntities.Data'.
This error occurs on the .toTraceString in the createcontext
the ssdl file has the defined type
Collapse
<EntitySetMapping Name="DataSet">
<EntityTypeMapping TypeName="IsTypeOf(ClientDataStoreEntities.Data)">
So it has to load the ClientDataStoreEntities.Data type which is the namespace and type of the STE library that i have generated from the model.
EDIT: with
var tracestring = context.CreateQuery<Data>("ClientDataStoreContainer.DataSet").ToTraceString();
It does seem to load all types , however now the service does not have any methods that i can call.
there should be 2 DataSet and PublishedDataSet but:
<service xml:base="http://localhost:1377/WcfDataService1.svc/">
−
<workspace>
<atom:title>Default</atom:title>
</workspace>
</service>
is what i get.
I ran into the same issue (the first one you mention). I have worked around using the suggestion by Julie Lerman in this thread. The other suggestion didn't work for me although I will experiment with them more since Julie's solution may have performance implications since it's executed (and has some cost) for every query.
MSDN Fail to work with POCO ModelContainer which entities are located in other assembly
Edit: Sorry, just realized you utilized the other solution mentioned in this thread.