I'm working on a web application that manages specimen freezers so our researchers can manage and inventory all the gross stuff they've made. A freezer looks like this:

1 Freezer
+- X Racks
   +- Y Boxes
    +- Z Cells
     +- 3 Cassettes
        +- 5 straws

So, pretty much what's going on is I have a potentially infinite pile of one object containing another object and so on and so forth. The catch is, I can also have something like this (Since we hold onto specimens for the criminal justice folks too):

1 Freezer
+- 24 Rollers
 +- 1 Cadaver
  +- X Evidence Bags
   +- Y Evidence Samples

Gross, especially since both options need to coexist in the same program and the same back-end.

I've thought about an object like this that describes what it is, and just stacking them up:

public class SampleContainer{
    public List<SampleContainer> ChildContainers { get; set; }
    public string ContainerType { get; set; }

But that runs me into trouble since I need to describe what's -in- the container as well, and that varies pretty wildly (Ie, is it a Cadaver or a mouse embryo?).

Are there any appropriate design patterns? What is the best way to model these relationships, without losing my or anyone else's mind?

  • Modeling recursive tree structures is hard in relational DB. But it is not unheard of. What research did you do? I'm sure there are lots of resources that should give you hints and ideas how to implement this kind of structure. For example, stackoverflow.com/questions/4048151/… , provides enough study material for a week. – Euphoric Dec 22 '17 at 20:34
  • @Euphoric: This isn't recursive at all (e.g. a freezer can't contain a freezer). – Brendan Dec 22 '17 at 20:49
  • 1
    @Brendan, but a Cadaver may contain a duck and subsequently a turkey. – MetaFight Dec 22 '17 at 20:50
  • @Brendan This is correct. There's definitely a 'top' here, but infinitely (potentially, though in practice it'll be 5-7) deep. – Adam Wells Dec 22 '17 at 20:54
  • 4
    Do you need a relational data model (or other kind of database, e.g. a document store) or just an object model? Does your program actually treat cadavers differently than mouse embryos, or are the contents of the containers meaningless to the program except for some metadata like a description or tags? This last question is really whether the contents can be treated uniformly or if they need to be modeled as well. – Derek Elkins Dec 23 '17 at 1:23

So long as the operations you need to "manage and inventory" are the same set of commands (print, count, etc) regardless of level, consider The Composite Pattern.

enter image description here

This will go as deep as you like. You can have different kinds of leafs that react differently to the same set of operations if you need them to. The nice thing is the operation to print the entire contents of the freezer is simply freezer.print().

  • Brilliant! Something similar to this (though it depended on a self-referencing Database Table in Entity Framework) was my initial thought. – Adam Wells Dec 26 '17 at 19:39
  • That sounds reasonable. Remember, representing this in a DB is a different issue. DB structures and OO patterns seldom have 1 to 1 mappings. See Object Relational Impedance Mismatch – candied_orange Dec 26 '17 at 21:04

Here's a thought:

public class SampleContainer{
    public string Description;
    public SampleContainer Parent { get; set; }
    public List<SampleContainer> ChildContainers { get; set; }
    public FrozenThing Contents { get; set; }


public class FrozenThing {
    public string Description;
    public SampleContainer Location;

Somewhere in your main code you might have a root container SampleContainer Facility, and you might also need a List<FrozenThing> AllThings;

You can see how you could browse the SampleContainers to find out what's in Freezer 5, Shelf 1, Tray 2, ... Test Tube 400.

You can also find the mouse part by searching AllThings then work backwards from that FrozenThing's Location via the Parents.

You might also want to do some Googleing for "C# generic tree data structures"


Step 1: Define an addressing scheme

For example; (depending on requirements, etc) you might decide to use a 64-bit unsigned integer such that:

  • bits 49 to 63 are used for "freezer number"
  • bit 48 is used as a "racks or rollers" flag
  • bits 40 to 47 are used as either "rack number" or "roller number"
  • bits 32 to 39 are used as either "box number" or "cadaver number"
  • bits 16 to 31 are used as either "cell number" or "evidence bag number"
  • bits 8 to 15 are used as either "cassette number" or the high half of "evidence sample number"
  • bits 0 to 7 are used as either "straw number" or the low half of "evidence sample number"

The point of this is to collapse everything down to an easily managed integer identifier that can be used in structure fields, keys in "key/value" stores, hash tables, array indexes, etc (that doesn't cause a "thrash caches with many levels of indirection and completely ruin efficiency" disaster).

Note: Instead of calling it an address you can call it a "universal location identifier" or something else. The name doesn't matter much.

Step 2: Determine the access patterns/usage

If the most common scenario is search (e.g. "find all things that contains "mouse") then you probably want something that is efficient for searching (e.g. maybe a set of indexes, with an index for each type of thing you might search for) but that usually means sacrificing efficiency for everything that isn't searching.

If the most common operating is lookup (e.g. "what is in freezer #1, rack #5, ...") then you probably want something that is efficient for lookup (e.g. maybe a set of variable length arrays) but that usually means sacrificing efficiency for everything that isn't lookup.

Step 3: Determine the best data structure/s to suit the access patterns/usage and the environment its used in

This requires more information than was provided. For example (assuming "SQL relational database"); maybe the only thing you need is a single flat table with 2 columns ("address" and "description of contents"), but that's very unlikely.

  • 1
    How do you plan on fitting a potentially infinite-depth structure in a finite length address? – MetaFight Dec 22 '17 at 20:49
  • @MetaFight: Excluding the misuse of the word "infinite" in the title; nothing about this is infinite. – Brendan Dec 22 '17 at 20:51
  • 2
    How do you plan on fitting an arbitrarily deep structure in a finite length address? – MetaFight Dec 22 '17 at 20:52
  • @MetaFight: Read the question - there's only 2 finite depths (both covered by my "address" format). – Brendan Dec 22 '17 at 20:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.