I'm developing a system that supports creating accounts and multiple users within every account that can each access a certain subset of data of their "parent" account.
The data is stored in a SQL Server database in the following tables:
Accounts: Id(guid, primary key), Title(nvarchar(200))
Users: Id(guid, primary key), Login(nvarchar), AccountId(guid, foreign key)
.
Now, I need to implement a concept of "Folders" and "Files" within accounts. Each account can have a number of files (an object with a name and a few other non significant properties) that can be arranged into folders (like a file system), and every user might have a permission to access a folder. "A user has permission to view a folder" means that this user can see all files within this folder and within all its subfolders. These folders/files also have to support a lot of moving around the hierarchy, renaming, editing, etc.
I have come up with the following table structure for this scenario:
Folders: Id(guid, primary key), Name(nvarchar(200)), AccountId(guid, foreign key)), ParentFolderId(guid, foreign key)
Files: Id(guid, primary key), Name(nvarchar(200)), FolderId(guid, foreign key),
UserFolderPermissions: Id(guid, primary key), FolderId(guid, foreign key), UserId(guid, foreign key)
This structure does the job of storing data correctly, but I also need to run some complex queries against it, like finding a complete path to a file or retrieving all files that current user has permissions to access. For that, I created a view that outputs all folders, files, and users who have permissions to access them:
WITH FolderWithPath AS
(
SELECT
folder.Id,
folder.Name,
folder.AccountId,
folder.ParentFolderId,
CAST('/' + folder.Name + '/' AS NVARCHAR(4000)) AS Path
FROM
dbo.Folders folder
WHERE
(ParentFolderId IS NULL)
UNION ALL
SELECT
self.Id,
self.Name,
self.AccountId,
self.ParentFolderId,
CAST(parent.Path + self.Name + '/' AS NVARCHAR(4000)) AS Path
FROM
dbo.Folders AS self
INNER JOIN FolderWithPath AS parent ON self.ParentFolderId = parent.Id
)
SELECT
file.Id AS FileId,
folder.AccountId,
folder.Id AS FolderId,
folder.Path AS Path,
userFolderPathPermissions.UserId AS AuthorizedUserId
FROM
FolderWithPath AS folder
LEFT OUTER JOIN dbo.Files AS file ON file.FolderId = folder.Id
LEFT OUTER JOIN
(
SELECT
UserFolderPermissions.UserId,
folder1.Path,
folder1.AccountId
FROM
FolderWithPath folder1
INNER JOIN UserFolderPermissions AS UserFolderPermissions ON folder1.Id = UserFolderPermissions.FolderId
) userFolderPathPermissions ON folder.AccountId = userFolderPathPermissions.AccountId AND folder.Path LIKE userFolderPathPermissions.Path +'%'
Now, this does seem to work, but I have certain performance concerns. Is it the best database structure to fit my needs? Is the query inside the view the optimal way to access the necessary data?
Due to different security issues, I am unable to test it in a real environment with millions of users performing hundreds of operations per second, so I would appreciate any advice regarding the code above.