Is it a problem if the car checks for the engine attributes and allows it or not to be a part of the car?
No.
That being said, your validation may be complex enough to introduce a domain service. Since two aggregates are involved you could have this:
car.Fit(engine)
Or this:
engine.Fit(car)
However, you probably want to be checking against a car model anyway :)
Since the rules are going to be somewhat more advanced and involve some data you probably want to introduce a domain service and possibly use double-dispatch on the objects:
So rather than car.Fit(engine)
you could have this:
car.Fit(engine, IModelServiceImplementation)
And in the Fit
method call:
if (!IModelServiceImplementation.CanFit(car, engine)) { throw new Exception(); }
The service could possibly load the correct model and rather check that against the engine. Depending on the domain one may even have modification levels and other rules to deal with.
Since a Car
instance would not contain the actual Engine
instance but only the EngineId
or possibly some value object there would be no real assignment of engine to car. You could still pass the engine instance to the car and have it create the association however it sees fit.
The solution proposed by 'Enrico S.' is possibly more relevant to scenarios where changes are effected on the aggregate roots where one may not have all the aggregate roots available or even where aggregate roots live in separate bounded contexts. Even if Car
and Engine
were in separate BCs one would probably be able to query the validity somehow. Some things are fine for eventual consistency but others may not be.
As usual there are many things to consider :)