Hi Bob, You got it right, Customers and Orders are aggregate roots, that's why I define two repositories. Anyway, that's a fake domain model, I just used familiar concepts to back my post.
I see your approach, thanks. That's a solution, I'm concerned, tough, on repeating my self on the definitions of relations. If the relation between Application and ApplicationUser changes I should check (besides the domain itself) the mapping code and the repositories code. Anyway, thanks for taking the time to answer, I appreciate it. Carlos > -----Original Message----- > From: Bob Hanson [mailto:[EMAIL PROTECTED] > Sent: Martes, 08 de Mayo de 2007 01:05 p.m. > To: [email protected]; [EMAIL PROTECTED] > Subject: Re: Kind of architecture question > > I think it really boils down to how you choose to implement > your domain. In your example below, why does Order reference > customer? Is Order an aggregate? If not, all access to Order > should be through Customer and then you don't need a reference. > > foreach ( Order order in customer.Orders ) { > Console.WriteLine( "Order #{0} from {1}", order.Number, > customer.Name ); } > > Otherwise, here are some things I have done: (.NET 2.0) My > domain classes implement IEquatable<T> which does a deep > comparison. I might not have an equal reference so I check > for data equality instead. The simplest implementation could > just compare Ids but that presents a problem when checking > for "dirty" data. > > Reference example: I have an Application class which contains > a list of ApplicationUsers (sub-class of User). An > ApplicationUser is a User of an Application (has a reference > to the Application) with a list of Roles for that > Application. My domain defines an interface > IApplicationRepository. I have a single repository implementation > (IBatisRepository.Repository) which implements all of my > repository interfaces. The repository method that returns an > application (with all of its application users via a sql > join) assigns a reference AFTER the query completes: > public Application GetApplication(string applicationName) > { > Application application = > SqlMapper.Instance().QueryForObject<Application>("SelectApplic > ationByName", > applicationName); > if (application != null) > { > foreach (ApplicationUser user in application.Users) > { > user.Application = application; > } > } > return application; > } > > > On 5/8/07, Carlos Peix <[EMAIL PROTECTED]> wrote: > > > > > > Hi Tom, > > > > Yes, I know that it's not IBatis concern, I'm not asking > Gilles to add > > support for this. > > > > But this operation mode (to stop calling this an issue :-) not only > > gives me different instances of the same object (I can fall in the > > trap modifying one object and reading another unmodified > instance in > > may code) but it have performance implications. > > > > Think for a minute in the example I posted (it's below you > answer in > > this post). Imagine that the customer holds a reference to the > > collection of orders, something like: > > > > Customer { > > // Mapped collection, with getter and setter, of course. > > private IList orders; > > } > > > > and the order has a reference to the Customer, just like > the example below. > > > > if I code this way: > > > > Customer customer = CustomerRepository.GetById( 1 ); > > > > and then I do (in another method, down the code path): > > > > foreach ( Order order in customer.Orders ) { > > Console.WriteLine( "Order #{0} from {1}", order.Number, > > order.Customer.Name ); } > > > > I'm loading the customer again with all the orders (I know > I can use > > lazy load for this or that I can send the original customer > instance). > > > > I just want to know how other people is handling this. > > > > Thanks > > > > Carlos > > > > > > ________________________________ > > From: Nguyen, Tom [mailto:[EMAIL PROTECTED] > > Sent: Martes, 08 de Mayo de 2007 11:28 a.m. > > To: [email protected] > > Subject: RE: Kind of architecture question > > > > > > > > > > > > I agreed with Sam that this should not be a concern for > iBatis. I've > > also battled with the same issues in the pass, but I've found that > > it's much easier to use SQL for controlling of identity and > > concurrency (through various methods such as comparison of > OriginalValue or LastModifiedDate). > > > > > > > > > > > > Repository implementation is a can of worm in itself. I > prefer to use > > light weight object and don't have to worry about issues such as > > multi-threading, caching and releasing references for Garbage > > Collector when it's not being reference. Also, you can't really > > ensure identical object references in a webfarm or multiple > application server SOA implementation. > > > > > > > > On the other hand, I had a very specific need of repository base on > > lookup business objects such as OrderType, BusinessType, > ContactType, > > etc… In this case, I implement custom in-memory caching > (repository). > > It's a very specific implementation which allow me to lazy load > > objects by identity > > (key) and type, cache, timely clearing of cache for GC, etc.. > > > > > > > > > > Regards, > > > > > > Tom Nguyen > > Sr. Developer > > > > > > > > > > > > > > > > > > > > > > On 5/7/07, Carlos Peix <[EMAIL PROTECTED]> wrote: > > > > > > Hi Shane, thanks for taking the time to answer. > > > > > > > > Yes, you are talking about an Identity Map I guess, but > this solution > > is harder to implement and tune. It's my last resort though. > > > > > > > > Of course, definitely the select="CustomerById" needs to be > removed. > > In fact, the command CustomerById uses a different cache that the > > command CustomerAll so, if we use cache for both commands > we can stop > > IBatis building different instances. > > > > > > > > One approach I used is for resolving this is implementing the > > CustomerRepository.GetAll() with an IBatis query (cached) and the > > CustomerRepository.GetById() resolved in memory. But I'm not very > > happy with this solution either > > > > > > > > Of course, the Order ResultMap just get the Customer Id and > I resolve > > the property getter or setter that way. > > > > > > > > class Order { > > > > > > > > // This field is mapped in IBatis > > > > object customerId; > > > > > > > > // this is a transient field > > > > private Customer customer; > > > > > > > > public Customer Customer > > > > { > > > > get { > > > > if ( customer == null ) > > > > customer = CustomerRepository.GetById( customerId ); > > > > return customer; > > > > } > > > > set { customerId = value.Id; } > > > > } > > > > > > > > } > > > > > > > > Carlos > > > > > > > > ________________________________ > > > > > > From: Shane Courtrille [mailto:[EMAIL PROTECTED] > > Sent: Lunes, 07 de Mayo de 2007 07:03 p.m. > > To: [email protected]; [EMAIL PROTECTED] > > Subject: Re: Kind of architecture question > > > > > > I'm just learning iBatis.Net now but I have used the repository <-> > > mapper pattern in the past. Usually what I have done is have the > > repository contain a reference to a cache. It checks the > cache before > > using the mapping layer to retrieve the item. The problem I see is > > your Order select="CustomerById". Without knowing more > about iBatis I > > would suggest you may need to remove that and instead have your > > repository fill in the reference after it gets the Order. > Definitely > > not a solution I'm in love with though. > > > > Shane > > > > > > On 5/7/07, Carlos Peix <[EMAIL PROTECTED]> wrote: > > > > > > Hi all, > > > > > > > > I used IBatis.NET with success in various projects now but > I am still > > not very happy with my implementations. I'll try to explain > my concerns. > > > > > > > > My environment is .NET 1.1 but I think .NET 2.0 is the same > thing. I > > should say that I try to work guided by the DDD principles, so I > > access the final store through repositories. > > > > > > > > I have, for example, an entity Customer (aggregate root or simply a > > persistent identifiable object) and a CustomerRepository with the > > following > > interface: > > > > > > > > Customer CustomerRepository.GetById( object id ); > > > > IList CustomerRepository.GetAll(); > > > > ... > > > > > > > > and I also have a Order and OrderRepository with the following > > interface > > > > > > > > OrderRepository.GetByNumber( int number ); > > > > ... > > > > > > > > The problem I face all the time with IBatis is the I get different > > instances if I do: > > > > > > > > // implemented with a Mapper.QueryForObject( "CustomerById", id ); > > > > Customer customer1 = CustomerRepository.GetById( object id ); > > > > > > > > // implemented with a Mapper.QueryForList( "CustomerAll" ); > > > > Customer customer2 = CustomerRepository.GetAll()[0]; > > > > > > > > // implemented with a Mapper.QueryForObject( > "OrderByNumber", number > > ); > > > > // and Customer mapped this way in the OrderResultMap: > > > > // <result property="customer" column="CustomerId" > > select="CustomerById" /> Customer customer3 = > > OrderRepository.GetByNumber( 100 ).Customer; > > > > > > > > But customer1.Id, customer2.Id and customer3.Id are the same. > > > > > > > > Ok, this is a situation that need to be controlled, > otherwise I could > > modify or check different instances of the same object. I was told > > previously that this is not an IBatis problem and I see why > (in fact > > IBatis doesn't know anything about object identity, so it > can't control this). > > > > > > > > The question is: how are you structuring your code to control that > > situation? there are some "recommended practices"? I > started with some > > ideas (one of them include IBatis cache configuration) but I'm not > > happy with any of them. > > > > > > > > Sorry about the long post and thanks in advance. > > > > > > > > Carlos Peix > > > > > > > > > > > > > > > > > > > > > > > > > > ________________________________ > > > > > > > > Princeton Retirement Group, Inc - Important Terms > > > > This E-mail is not intended for distribution to, or use by, > any person > > or entity in any location where such distribution or use would be > > contrary to law or regulation, or which would subject > Princeton Retirement Group, Inc. > > or any affiliate to any registration requirement within > such location. > > > > This E-mail may contain privileged or confidential > information or may > > otherwise be protected by work product immunity or other > legal rules. > > No confidentiality or privilege is waived or lost by any > mistransmission. > > Access, copying or re-use of information by non-intended or > > non-authorized recipients is prohibited. If you are not an intended > > recipient of this E-mail, please notify the sender, delete > it and do > > not read, act upon, print, disclose, copy, retain or > redistribute any portion of this E-mail. > > > > The transmission and content of this E-mail cannot be > guaranteed to be > > secure or error-free. Therefore, we cannot represent that the > > information in this E-mail is complete, accurate, > uncorrupted, timely > > or free of viruses, and Princeton Retirement Group, Inc. > cannot accept > > any liability for E-mails that have been altered in the course of > > delivery. Princeton Retirement Group, Inc. reserves the right to > > monitor, review and retain all electronic communications, including > > E-mail, traveling through its networks and systems (subject > to and in > > accordance with local laws). If any of your details are > incorrect or > > if you no longer wish to receive mailings such as this by > E-mail please contact the sender by reply E-mail. > > > > ________________________________ > > > > > > > > ________________________________ > > > > > > > > > > This e-mail message and any files transmitted herewith, are > intended > > solely for the use of the individual(s) addressed and may contain > > confidential, proprietary or privileged information. If > you are not > > the addressee indicated in this message (or responsible for > delivery > > of this message to such person) you may not review, use, > disclose or > > distribute this message or any files transmitted herewith. If you > > receive this message in error, please contact the sender by reply > > e-mail and delete this message and all copies of it from > your system. > > > > ________________________________ > > > > > > > > > > > > > > > > > > > > > > >

