Images in the BO - Reference Path or BLOB ? (Smart Client)

Images in the BO - Reference Path or BLOB ? (Smart Client)

Old forum URL: forums.lhotka.net/forums/t/384.aspx


brettswift posted on Thursday, June 15, 2006

Hi, I just finished reading a couple posts having to do with a Smart Client with support for disconnected data.  Sounds interesting - I'm thinking of using SQL Anywhere - so keep this in mind when you make any suggestions to my question please!

I have a little application where for one BO I need to have the user upload a photograph for the object.  I am not sure how I should handle this in my Business model...  When I designed the classes I built in a string field called "PhotoPath"  which would be a reference to a directory on the server... Now I'm not sure what do do with this..  in an ASP.NET page it would be a little simpler, but still, the concept of making your Business Objects manage the uploading and storing of a photograph is kind of interesting.

I went with a string field to reference a path, because I was trying to think of overhead.  Would it be best to store this as a BLOB ?

Things get more complex in disconnected mode (a mode i still have to figure out - its my first disconnected smart client!) because I'd like to cache the images on the client as well - this may be easier with a BLOB field, because with a reference path I'd have to have a file directory on the users computer as well.


Any thoughts?

odie replied on Thursday, June 15, 2006

brettswift,

My first app in CSLA a few years ago was document control program, though disconnected data was not really an issue.

I don't know if this was the best way to handle the images but this is what we did: (at least I will try and remember what I did)

All images were saved to an SQL database as a BLOB file as you are thinking of doing. The user selected the path and image file they wanted to attach. Then when the user saved the data I then went out and grabbed the image file(s) and stored them inside the BO as a filestream (before calling mybase.save). This had to be done while the BO is on the current users machine, if you used remoting once you got the server you would not have access to the image file the user wanted to attach. Once this was done I then called the BO's mybase.save as you would normally.

When a user loaded a record from the database I would not return the image, just the metadata. I had a seperate function for retrieving the image and storing it in a temporary directory on the users machine for their referece. The user had the option of viewing the image or signing out the image/record for their use to prevent modifications by someone else.

Once a record had been saved subsequent changes to the record ignored the image unless they wanted to overwrite the existing on on the server. This was to avoind unwanteded network traffic.

We also implemented a function to allow batch uploading of images to the server so the metadata could be entered first. This was due to the fact we were working with over 100,000 records. Each record was automatically assigned a Barcode number then when the image was scanned the file was named the barcode number which was used during the batch upload to know which file to attach the image to.

With .NET 2.0 there is a new feature to allow your images to be compressed prior to uploading to save space on the database.

Hope this helps,

RobO

brettswift replied on Thursday, June 15, 2006

Sounds interesting, and sort of what I thought would have to happen.

You say you had "a seperate function for retrieving the image and storing it in a temporary directory on the users machine for their referece.".  This function I'm assuming is at the GUI level, not on the client side BO correct?  I'm guessing each time the BO ran, it would have to check for a local copy of the image, which if exists, would override the one from the DB - which makes things tricky when the user uploads a new image in place of the old one - or if another user does that, and all other users have an old cached version of it that won't update, because the image exists... hmm. .

Also, you say that changes to the record ignored the image property after it was uploaded.  I'm guessing you did something like having a write-only boolean property called "OverwriteImage" so when your save method runs, it hits a condition and knows it has to save the image file as well ?


odie replied on Thursday, June 15, 2006

The function for retrieving the image I wrote as a seperate kind-of get function within the actual BO that simply went out and grabbed the BLOB and returned it back to the user where it was then converted back into the original file. I had a default location where all images were put for viewing purposes only. Thus the user could not assume the file was the current version, just a reference. Thinking about in now once the program closed it cleaned out this temporary location to keep getting overloaded with un-needed images.

The check-out function was similar except it stored the image in a permanent location in the user's machine. The user who signed out the image had to ability to revise the image/metadata on the server which made a new revision (the old data was never overwritten for history purposes) and in fact the new image was given a new barcode number so you always know what version when with what metadata. BTW the program printed out barcodes that were then stuck onto the document being scanned so any time the image was printed you know what record it related to.

For downloading it was all in the user's hands to initiate the transfer. One other note, once a record was created and an image uploaded it could not be modified without first being checked out. Although we implemented a quick checkout/edit/checkback in option on the form to allow a correction of metadata all in one step, but images could not be modified (reattached) unless they first check them out. 

As for your last question, I actually checked the file path field for a value. If the user never selected an image then this was blank and hence no image needed to be uploaded. We really were not interested in keeping track of where the file originally was uploaded from so this information was not stored in the database just it's name and extention.

When it came to viewing the file the program simply used shell (I think) with the path/filename and extension and I let Windows determine which program to use to view the file. This of course was called after the file was saved back to the user's computer.

I might suggest looking at maybe creating a command object for dealing with uploading and downloading of images and I would create a seperate field in your table like IsImageAttached if you need to ever query the database to find records that do/don't have an image attached. If you include the BLOB field you will be waiting a while as you database grows. Only deal with the BLOB field when you absolutely have to.

Regards,

RobO

PS. just noticed your in Calgary as am I.

brettswift replied on Thursday, June 15, 2006

Thanks for your tips.

Haven't noticed any other Calgarians on here.  Actually this is just a project I'm working on for a family friend, might get them to give me a chunk of cash for it we'll see haha.   Currently looking for work right now, so this is pretty much the first CSLA project I've done.   Does your company use CSLA ? Or are you a contractor and use it yourself with clients?

odie replied on Thursday, June 15, 2006

I've had a several people contact me lately looking for developers maybe I can direct you to them for work.

I sent you my contact info in a private post...

Regards,

RobO

jwooley replied on Tuesday, June 27, 2006

As an answer to your subject line, I would offer None of the above. Here's an overview of the solution I have used:

The business object contains some metadata about the file (who uploaded it, when it  was uploaded, file size, etc). It also contains a property which is a Byte Array containing the actual contents of the blob. This array is lazy loaded from some data source which would need to use the same distributed domain boundaries as my application, and thus pumped through the DataPortal.

Originally I wrote it with a blob in the database. Since the files I was pumping into this were 200+ page Mortgage packages, putting 25meg  blobs in the database each time got to be a strain on the database server (and was part of the reason why I lazy loaded the byte array). Eventually I decided it would be better to move the contents of the blob data to another location. I decided to extract the files to an FTP store with guid file names on the actual data store. To make the change, I only needed to modify a couple methods in the BO (the lazy loaded command object and the dataportalUpdate).There were no changes to the UI as it just interacted with the same byte array. To display the data back to the user, I just stick it in a temporary file store and launch it with the approprate editor as necessary.

I have had no problems with that implementation since I deployed it while I have added 3 gig to the store. The database hums along now rather than choking on the re-indexing while resizing the database. There is an old demo of the blob method available at http://avbsg.net/Uploads/FileManCSLA.zip

Jim Wooley
http://devauthority.com/blogs/jwooley/default.aspx

Copyright (c) Marimer LLC