Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

According to best practices is it a bad idea to cache features and geometries inside business objects? If it is bad, what is the alternative way?

References to features may be replaced with their Ids, but what about geometries?

share|improve this question
add comment

2 Answers

You do not describe in detail what exactly are your business objects. It is a largely overloaded term and many people tend imagine very different things.

Given that your business objects are the same as domain objects in the sense of traditional domain-driven design, I am gonna suggest the exact opposite of blah238's answer (even though it contains a lot of valuable information) - do NOT keep references to geodatabase objects in your business objects.

The rationale behind this suggestion might not be applicable for the simplest applications, but please bear the following points in mind:

  1. Most geodatabase objects, be it a workspace or an individual row, are a effectively a handle to geodatabase resource. In case of SDE or direct connect, it translates to a network connection to SDE/database. For local geodatabases, it might result in a lock on a filesystem resources. Now, in a reasonably layered design, you most certainly would NOT keep a reference to a network connection (or an abstraction like the repository) in your business objects. You are doing exactly that when holding onto geodatabase objects.
  2. As stated in other answers and comments, references can be held only onto rows produced by a non-recycling cursors. For one, switching from a recycling cursor to non-recycling has performance implications. But more importantly, changing the underyling data fetching mechanism solely for the purpose of your domain breaks the principles of loose-coupling. Whenever you can capture the data in your domain object instance, you can do so for both recycling and non-recycling cursors equally provided you do not keep the reference to the underyling row.
  3. Related to 2., one has to ask what is the real purpose of your business objects? Do they keep any state themselves, or do they rely solely on the data contained in the kept IRow instance? Seems like your business objects are just some functionality (methods containing business logic) operating on an IRow instance. This, again, comes down to your design and what exactly you consider to be business objects, but a crafty mapping between IRow fields and your business object properties at the time of reading them from the geodatabase will give you a much cleaner domain model and get rid of the IRow dependency.
  4. Whenever you couple your domain model classes with a geodatabase-related objects, your code almost automatically becomes untestable with unit testing. That is, unless you are willing to undertake mocking ArcObjects, which is virtually crazy. See How to unit test ArcObjects with Mocking for more details.
  5. There are also few rules to follow when holding onto IRow references which further make your life harder. When editing, you must discard and refetch IRow references on several occasions, e.g. when starting an edit session or upon undo/redo. See the bottom of IWorkspaceEdit documentation for a more thorough discussion.
  6. Similarly to 5., in a multi-user geodabase environment, references to tables, feature classes etc. need to be refreshed when a geodatabase version changes.

Now, again, validity of all of these points largely depends on your particular scenario and needs. Holding onto ArcObjects is obviously not prohibited and I do that myself on occasions. You just need to be aware of the implications, of which there are many. As I tried to hint, some of these are technically purely ArcObjects-related, some are more of a higher-level software design nature.

share|improve this answer
    
+1, these are some good points especially regarding loose coupling, but in some cases performance trumps design ideals. In my case I found it much faster to keep a strong reference to feature classes because the cost of connecting to and disconnecting from feature classes frequently was too severe. I could have probably written a data access layer to manage the connections to feature classes independent of the business objects but this was a very small ArcMap extension, not a standalone application. I do not think there is any hard and fast rule so it's good to have multiple perspectives! –  blah238 Mar 26 '12 at 21:53
    
For now I cache both geometry & features references in my BO. BO themselves hold feature`s field valued in private fields and expose them through public properties. They also have some domain logic and preform CRUD operations on features. –  megadrofan Mar 27 '12 at 21:31
    
So I want to follow best practices in software development during refactoring this nightmare(I`m on a long way of studying).So to achieve loose coupling it is better to break application into layers and separate ArcGis API through DAL and utility classes and use some interchangeable storage of GIS specific data in domain model(like WKB)? –  megadrofan Mar 27 '12 at 21:57
    
You can keep geometries as references to IGeometry instances as long as you get them through a non-recycling cursor or using IGeometry.ShapeCopy. Other than that, yes, for larger applications I would introduce dedicated business layer. For smaller extensions, is is most likely an overkill. –  Petr Krebs May 1 '12 at 17:34
    
I recommend reading "Domain-Driven Design: Tackling Complexity in the Heart of Software" by Eric Evans, it will give you an interesting perspective on design. With that, it will also give you new interesting challenges and things to think about on how to do good design with ArcObjects :-) –  Petr Krebs May 1 '12 at 17:36
add comment

In general this shouldn't be a problem but there are some objects in the ArcObjects library that you want to be very careful about managing their lifetimes so that you don't tie up critical resources or keep locks on database tables for extended periods.

Among lots of other good info, in this thread James MacKay lists some of the types of objects you should take special care with:

  • Cursors
  • Datasets, i.e. tables, feature classes, feature datasets, rel. classes (but excluding name objects)
  • Workspaces (inc. versions, if you're connecting to multiple versions of an enterprise GDB at once)
  • Rows, features and attributed relationships
  • Row buffers and feature buffers

If you are using .NET then you should be aware that it is a garbage-collected environment, and COM objects are not necessarily released as soon as they go out of scope, but can linger on until application shutdown unless you explicitly release them, call GC.Collect() (not recommended), or the GC finally decides to clean them up on its own. For more info see Releasing COM references in the ArcObjects SDK help.

I think storing row IDs instead of rows themselves is a good idea, but you should be okay storing geometries that you create as long as memory consumption is not a problem. As @Ragi mentions below, if the geometries are coming from a recycling feature cursor, be sure to use IFeature.ShapeCopy to create a clone of the feature's geometry. I am also assuming your business objects will not need to be serializable, which could complicate matters.

I have stored IFeatureClass references (which keep connections open to their source workspaces) in business objects and implemented logic to specifically release them as soon as they were no longer needed (see Implementing a Dispose Method, if you are using .NET, for the MS-recommended dispose pattern, and IDisposable: What Your Mother Never Told You About Resource Deallocation for a better understanding).

share|improve this answer
    
Thanks the answer. I'm aware of managing objects lifetime in ArcObjects, and always try to release unused references :) I worry about threading issues in ArcObjects, may be caching references in BO is bad idea, as they may reference some kind of shared resource. Because I faced some kind of non repeated errors in ArcGis with geometry and TopologicalOperator - incorrect buffer results, sudden hangs. –  megadrofan Mar 26 '12 at 11:49
    
The ITopologicalOperator is its own can of worms -- perhaps ask a separate question about the issues you are having with it. –  blah238 Mar 26 '12 at 16:49
2  
If you want to hold FeatureClasses or other objects, it should be OK. Just remember you are keeping them alive. For geometries, it depends where you got them from. For recycling cursors, you should never hold a reference to them - that's the COM contract for that interface. If you do want to keep them, then clone them (since that would be your copy). Holding ids of features is acceptable, too, since if you are editing, ArcObjects will keep the internal caches in-sync for you. –  Ragi Yaser Burhum Mar 26 '12 at 16:59
    
I suppose keeping a reference to features within a classextension would violate this rule. –  Kirk Kuykendall Mar 26 '12 at 20:22
    
@blah238: I wonder what your Dispose() method looks like.. if it contains Marshal.ReleaseComObject, it most likely does not have the desired effect since you cannot be sure how many times to call this method. If it contains Marshal.FinalReleaseComObject, you risk releasing a RCW which some other managed code is still referencing, which can be fine only in very specific scenarios (e.g. a standalone application, or when you are about to delete the feature class). In other words from my point of view, the dispose pattern makes little sense on IFeatureClass references except few cases. –  Petr Krebs Mar 26 '12 at 20:53
show 8 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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