8

I'm using memcache behind a web app to minimize the hits to our SQL database. I'm storing C# objects into this cache by marking them with SerializableAttribute. We make heavy use of dependency injection via Ninject in our app.

Some of these objects are large, and I'd like to break them up. However, they come from a single stored procedure call (i.e. one stored procedure call gets cooked into the full object graph), and I'd like to be able to break these objects up and lazy-load specific subgraphs from the cache separately rather than load the entire object graph into memory all at once.

What are some patterns that would help me accomplish this?

leppie
  • 115,091
  • 17
  • 196
  • 297
FMM
  • 4,289
  • 1
  • 25
  • 44
  • So I guess one my questions would be, why is the object so large -- or rather, how is it being used that you can't just send back the fully loaded object? Is it being returned over a service or something? If that's the case, then I think you need to segregate those contracts more appropriately, which sounds like it will require some pretty hefty refactoring. – Sinaesthetic Mar 21 '13 at 17:07
  • If I understand you correctly, I'm pretty sure you can do this with our library Patterns.NET @ www.nubilosoft.com . It sounds as simple as doing Lazy.Create(..), which basically wraps a lazy-loading wrapper around an object. Also not sure if it applies here, but I'd also have a look at the Flyweight. – atlaste Mar 22 '13 at 07:42
  • @Sinaesthetic: In this case, the large-grain problem of the stored proc call is a reflection of a poorly-designed legacy schema, the modification of which is out-of-scope. – FMM Mar 22 '13 at 13:22
  • How is this/these object(s) being used in the end? Are they being piped out of a service? I ask because I mean, if the object is already pulled out of the database and built, and you cache it, then... it's already there, so I'm not sure I see the benefit of attempting to "lazy load" something that's already in memory. ?? – Sinaesthetic Mar 23 '13 at 08:01
  • If what you mean is that you're building many objects and caching them but are just trying to find a pattern that allows you to lazy load THOSE objects into another object which you have created, then the pattern below will still work. But instead of the database being your repository, you use your cache instead. Then just use the typical getter/setter method get{ return _myProperty ?? (_myProperty = lazyGetFromCacheRepository()) }; – Sinaesthetic Mar 23 '13 at 08:05
  • In this scenario, it's a web app. Some requests use some subgraphs of the big object, other requests use other subgraphs, often with quite a bit of overlap. Often, the root of the object graph is all that's needed, though. – FMM Mar 25 '13 at 13:51
  • I always check with Martin Fowler first: [martinfowler.com/eaaCatalog/lazyLoad.html](http://martinfowler.com/eaaCatalog/lazyLoad.html) – Mikael Härsjö Feb 08 '12 at 20:07
  • I might actually approach this the same way. Since your big momma object is being built from the database whether you want it or not, just cache that and transfer the pieces that you need from it into dtos that are sent back to the client, using the same pattern that I put in my answer. So if Obj1 contains member1 and member2, and the client only needs member2, then create a dto class for member2 that only has what the client needs, then build that from your cached object and return it. – Sinaesthetic Mar 26 '13 at 19:15
  • This wouldn't actually require lazy loading and would give you the opportunity to clean up the overall service pattern. Have the client request the specific endpoint that calls the right operation to build the correct dto. – Sinaesthetic Mar 26 '13 at 19:17
  • I added another diagram to my answer – Sinaesthetic Mar 26 '13 at 19:31

2 Answers2

4

As far as patterns go, I'd say the one large complex object that's built from a single stored procedure is suspect. I'm not sure if your caching is a requirement or just the current state of its implementation.

The pattern that I'm used to is a type of repository pattern, using operations that fill specific contracts. And those operations house one or many datasources that call stored procedures in the database that will be used to build ONE of those sub-graphs you speak of. With that said, if you're going to lazy load data from a database, then I can only assume that many of the object members are not used much of the time which furthers my point - break that object up.

enter image description here

A couple things about it:

  • It can be chatty if the entire object is being used regularly
  • It is fully injectable via the Operations
  • The datasources contain the reader for the specific object, thus only performing ONE task (SOLID)
  • Can be modified to use Entity Framework, without too much fuss
  • Can be designed to implement an interface, making it more reusable
  • Will require you to break up that proc into smaller, chewable pieces, which will likely only benefit you in the long run.
  • The complex object shown in this diagram really shouldn't exist if only parts of it are going to be used. Instead, consider segregating those objects. However, it really depends on how this object is being used.

UPDATE:

Using your cache as the repository, I would probably approach it like this:

enter image description here

So basically, you store the legacy object, but in your operations, you use them to build more relavent DTOs that are returned to the client.

Sinaesthetic
  • 11,426
  • 28
  • 107
  • 176
  • "[T]he one large complex object that's built from a single stored procedure is suspect." You're absolutely correct; however, this is a design constraint for me. I can't change this. – FMM Mar 22 '13 at 13:24
2

I know NHibernate does lazy loading buy replacing objects with proxy objects. Then in the proxy object there is some kind of check that causes the loading of the real object the first time you try to access the object.

I'm not sure of any Design Patterns that would cover that, but you could look at the Nhibernate source code.

A down side of using proxy objects is you have to be careful with inheritance and type checks as you could be checking the type of the proxy and not the actual object.

eaglestorm
  • 1,192
  • 1
  • 13
  • 32