Perhaps for the nightly import you could look at using events which
are then consumed by your domain layer? For example we have a similar
situation - data coming in from a mainframe in a nightly batch. The
data coming in needs to be mapped to our internal identifiers as well
as other processing so we do the "dirty work" outside of the domain -
file parsing, processing and mapping and the result is a collection of
events which are sent as messages (in our case we're using NServiceBus
+ MSMQ) to the domain layer - an example would be an "AccountClosed"
event message that contains our account GUID and a message as to why
the account was closed. That message is then published using
NServiceBus and a subscriber receives the message and processes it,
invoking the "CloseAccount" behavior of the Account aggregate. That
behavior could then be reused elsewhere - the UI could also send a
"CloseAccount" message to the domain (similar to how your MVC
application is operating today) and the result would be the same -
account.CloseAccount() would be invoked with whatever rules are
contained internally. In addition we can scale out the batch import
process horizontally, again making use of the infrastructure provided
by NServiceBus with the notion of a distributor to spread the load.
The biggest hurdle will be to move off the SSIS process - I'm sure
your DBA or whomever has optimized the hell out of that with set-based
operations to deal with the data being imported irregardless of the
business rules contained in your domain but the key in my case was the
scalability story of horizontal vs. vertical scale-out and removing
duplication of business rules in the SSIS package and the domain layer
and the resulting maintenance headaches that ensue.
Hope that helps,
Matt
On Tue, Jul 14, 2009 at 1:21 PM, jlembke<lembkebus@...> wrote:
> Thanks Richard,
>
> I see what you are saying, so to eludicate a little, we started regarding
Return as an Aggregate itself because they come into the system in two ways: 1)
as an element of another Aggregate Root called "Return Authorization" which
would be a collection of return items and the business rules surrounding
returning a list of "return items". These would be in our main MVC application
2) returns also come into our system's sql database from a mainframe invoicing
system via SSIS. This is a nightly batch job and we import records and insert
them. The same rules for inserting a "return item" from an authorization in our
application must also be applied to returns being inserted from our mainframe
invoicing system, so we reference the domain and repository assemblies from the
ssis package.
>
> Maybe we are being too clever by half, but we wanted the same domain logic to
govern both processes.
>
> So to reiterate what that domain logic is: In our domain, a return must be
applied to an existing purchase. Purchases and Returns are two different tables.
To associate the two, we have a "ReturnsApplied table that takes the newly
inserted Return key, the related Purchase key, and a quantity. This helps us
track what quantity was returned against which purchase.
>
> Maybe we shouldn't be trying to re-use Domain objects for the nightly import
at all?
>
>
> --- In domaindrivendesign@yahoogroups.com, Richard Dingwall <rdingwall@...>
wrote:
>>
>> On Fri, Jul 10, 2009 at 9:57 AM, jlembke<lembkebus@...> wrote:
>> >
>> >
>> > There is a big design flaw here, but I'm having trouble solving it:
>> >
>> > The business need is a little involved so I'll try to keep this simple.
>> > We have a table with purchases, and a table for returns. When a return is
>> > made, we have to find match that return to the oldest purchase in the db,
>> > and record that in a "returns applied" table.
>> >
>> > So, when I insert a Return, within that transaction, I need to apply the
>> > return to a purchase record.
>> >
>> > As it stands now, we have a service that calls the repository for the
>> > insert. The service needs to know what the key is of that inserted record,
>> > so that it can finish the transaction by inserting an "applied" record
using
>> > that key.
>> >
>> > We're basically stuck because my understanding is that a repository should
>> > not return this kind of data. Doesn't this defeat the idea of the
Repository
>> > being a collection?
>>
>> Yes definitely, it's leaking persistence artifacts into the domain.
>>
>> In your domain model, is Return really an aggregate root by itself? Or
>> are Returns just a collection on the Customer entity?
>>
>> E.g. instead you might have:
>>
>> customer.Return(customer.Purchases[0]); // adds to the
>> customer.returnedPurchases collection
>> customerRepository.Save(customer);
>>
>> This would negate the need for a ReturnRepository completely.
>>
>> --
>> Richard Dingwall
>> http://richarddingwall.name
>>
>
>
>
>
> ------------------------------------
>
> Yahoo! Groups Links
>
>
>
>