Not sure I understood the question completely, but I'll describe they way we solve the same task (with the only difference that we made a library of arbitrary documents).
Primary DB entry is docs table:
Id -- file id, pk
UserId -- owner id
Size -- file size in bytes
FileName -- name to display like 'img.jpg'
ContentType -- image/jpg
FileLocation -- location of the file on filesystem.
-- in our case it was something like {storage-root}/{userid}/{guid}
ThumbLocation -- location of a preview version of the same file.
Created -- upload time
So upload algorithm:
- Get a file from a user.
- Create empty
Document
object conforming to the structure of the table above. - Set
doc.FileName
to the original filename ("img.jpg"). - Caclulate destination folder at filesystem per template '/files/{userid}'.
- Generate unique file name (Guid.New()) and save its value in
doc.FileLocation
. - Write file to
doc.FileLocation
. - Set
doc.Size
to the original file size. - If it's an image, generate preview file, generate it's name:
doc.ThumbLocation = doc.FileLocation + "thumb"
. - Write thumb file.
- save
doc
to DB.
When user requests file list (by url like /files/{userid}
):
- Read all user's documents from a database
- (Note that sorting options are not affected by physical files and their locations. All required information is already in the table).
- Show user a list of documents.
- Each record shows
doc.FileName
,doc.Size
, and a link pointing to/files/{userid}/{fileid}
When user requests a file by url like /files/{userid}/{fileid}
):
- Read doc from the database
- Load file from
doc.FileLocation
- Send it to the user.
As a conclusion: we manage physical files and locations only on upload time. The rest of operations are based only on the data we have put to the database. Then getting files content we rely on paths written to the table as it and do not bother their exact meaning.