Multiple connections to a SQL Server Compact Edition database on a network share Part 2

You Can Take it With You

Syndication

News

  • Don't miss the next Windows Mobile Webcast... Unit Testing for Mobile Devices: http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032382824&EventCategory=4&culture=en-US&CountryCode=US.

I mentioned in my post yesterday that SQL Server Compact Edition doesn't support multiple concurrent connections to a database file located on a network share. In systems where we control the configuration avoiding this scenario is easy. It occurs to me, however, that many systems are end-user configurable which means that the user may choose a network share as the home for the database file for any number of reasons.

As a result, it's important for any Notebook/Desktop computer or Ultra-Mobile PC application that might possibly have multiple concurrent connections to a SQL Server Compact Edition database to include a check to verify that the database file is not located on a network share. Failing to do so, could lead to difficult to diagnose system issues down the road.

The .NET code to determine a path's drive type uses the .NET Framework's System.Management.ManagementObject class. For simplicity I've wrapped the various steps into individual functions. All of the functions work with both absolute and relative pathnames and the path does not have to actually exist.

  • IsPathOnNetworkDrive: Identify whether a file is located on a network share
  • GetDriveTypeForPath: Determine a file path's drive type (local, network share, removable, etc.)
  • GetDriveNameForPath: Retrieve the drive specification for a path (C:, K:, Z:, etc.)
 
/// <summary>
/// Determines whether a file path is located on a Network Share
/// </summary>
/// <param name="pathName">Absolute or relative pathname of the file.
/// The pathname is not required to currently exist</param>
/// <returns>True if file path is located on a Network Share</returns>
static bool IsPathOnNetworkDrive(string pathName)
{
  return GetDriveTypeForPath(pathName) == DriveType.Network;
}
 
/// <summary>
/// Identify a file path's drive type (local disk, network share, removable drive, etc.)
/// </summary>
/// <param name="pathName">Absolute or relative pathname of the file
/// The pathname is not required to currently exist</param>
/// <returns>A DriveType enumeration value identifying the device type where the file path is located</returns>
static DriveType GetDriveTypeForPath(string pathName)
{
  DriveType driveType = DriveType.Unknown;
  string driveName = GetDriveNameForPath(pathName);
 
  string driveObjectname = string.Format("Win32_LogicalDisk.DeviceID=\"{0}\"", driveName);
  ManagementObject driveObj = new ManagementObject(driveObjectname);
  driveObj.Get();
  PropertyData driveTypePropertyData = driveObj.Properties["DriveType"];
  if (driveTypePropertyData.Value != null)
    driveType = (DriveType)Convert.ToInt32(driveTypePropertyData.Value);
 
  return driveType;
}
 
/// <summary>
/// Identifies the drive portion of a file path
/// </summary>
/// <param name="pathName">Absolute or relative pathname of the file
/// The pathname is not required to currently exist</param>
/// <returns>A string containing the drive portion of the file path. The drive string contains the colon
/// i.e. C:, K:, Z:, etc.</returns>
static string GetDriveNameForPath(string pathName)
{
  string pathRoot = Directory.GetDirectoryRoot(pathName);
  int idxSeperator = pathRoot.IndexOf(Path.VolumeSeparatorChar);
  string driveName = pathRoot.Substring(0, idxSeperator + 1);
 
  return driveName;
}
 

What I found kind'a interesting is the difference between the .NET code and the native code to determine if a path is on a network share. It turns out that for native developers, one can just use the GetDeviceType API call rather then needing to create and access the management objects as .NET requires. I understand why the .NET code is so different; it's using a standardized mechanism for identifying and managing parts of a system. That said, in this case it does seem like a fair amount of overhead.

If you don't mind using P/Invoke to call out to native code, you can call out to the Win32 GetDriveType API as is done in the following version of GetDriveTypeForPath which is much more lightweight than the version of GetDriveTypeForPath shown above.

/// <summary>
/// Win32 P/Invoke to GetDriveType
/// </summary>
/// <param name="pathName">Drive specification including the colon - i.e. C:, K:, Z:, etc.</param>
/// <returns>An UInt32 value identifying the drive type. Actual #define values are defined in
/// WinBase.h - the values returned by this function correspond directly to the .NET DriveType enumeration</returns>
[DllImport("Kernel32.dll")]
static extern UInt32 GetDriveType(string pathName);
 
/// <summary>
/// Identify the type of drive (local disk, network share, removable drive, etc.) a file path
/// is located on.
/// </summary>
/// <remarks>This function uses P/Invoke to call out to a Win32 API function and therefore may introduce
/// significant Code Access Security Concerns</remarks>
/// <param name="pathName">Absolute or relative pathname of the file
/// The pathname is not required to currently exist</param>
/// <returns>A DriveType enumeration value identifying the device type where the file path is located</returns>
static DriveType GetDriveTypeForPath(string pathName)
{
  string driveName = GetDriveNameForPath(pathName);
  return (DriveType) Convert.ToInt32(GetDriveType(driveName));
}
 

As lightweight as the second choice is, it does introduce significant concerns from a Code Access Security standpoint because you're calling directly into native code. In general I'd gravitate to the first (pure .NET) solution but I wanted to show both choices.

Whatever technique you choose to use, from the standpoint of SQL Server Compact Edition, the most important thing is that any application that opens multiple concurrent connections to a SQL Server Compact Edition database include a check to verify that the database isn't located on a network share.

BTW: I want to thank Ted Neward, Dan Sullivan, and Jason Whittington for their help and opinions during the debate over the two GetDriveTypeForPath  implementations. J

 


Posted Feb 19 2007, 08:27 AM by jim-wilson

Comments

Mac Dude wrote re: Multiple connections to a SQL Server Compact Edition database on a network share Part 2
on 04-16-2007 2:44 AM
I disagree. Steve Jobs would have done it much better.
Jim Wilson wrote re: Multiple connections to a SQL Server Compact Edition database on a network share Part 2
on 04-16-2007 6:52 AM
Mac Dude;

I'm not sure what you're disagreeing with. This post and it's predecessor state some technical details and don't have much opinion. There's certainly not anything that says that Microsoft has done a better job about something as compared to other organizations.

I'm interested to know what it is you disagree with. Could you post another comment offering more detail?

- Thanks, Jim
Jon wrote re: Multiple connections to a SQL Server Compact Edition database on a network share Part 2
on 08-20-2007 6:44 AM
I tried to find out if I could connect to the same .sdf file by writing in two different programming language(VB.NET and C++). VB.Net accessing .sdf with all the bells and whistle application UI presenting data retrieve from it, and Native C++ applications to mainly inserting data for fast operation and made this C++ apps as a service.

I was wondering if this can be done?.(By opening multiple connections), and if there will be any issue. (multiple apps, multiple connection, one .sdf)

Probably a sample in Native C++ can bring me up to speed on how to write one in C++ (I've created an apps with .NET)

Can you point out some documentation on multiple data access concurency/locking SSCE offer?.
Jim Wilson wrote re: Multiple connections to a SQL Server Compact Edition database on a network share Part 2
on 08-20-2007 7:40 AM
Jon;

SSCE will work just fine with multiple programs concurrently accessing/modifying the same database. It doesn't matter whether they are in the same language or if they are in different languages. The only requirement is that the database cannot be located on a network share; it must be on a local disk.

Support for multiple concurrent connections safely modifying the database was introduced in SQL Server Compact Edition 3.0 (known as SQL Server Mobile Edition at the time). The current version of SQL Server Compact Edition is 3.1 and continues to support multiple applications and/or threads concurrently updating the database. (SQL Server Compact Edition 3.5 is included with Visual Studio 2008)

A good place to learn more is the link below. It covers multiuser access, concurrency, transactions, isolation levels, and locking.
http://msdn2.microsoft.com/en-us/library/ms171959.aspx

I hope that helps.

Jim
Jon wrote re: Multiple connections to a SQL Server Compact Edition database on a network share Part 2
on 08-21-2007 9:31 AM
Hi Jim,

Thanks a lot!. You really saved my day.
One more question if you do not mind, in SSCE, there is a default value field for a column. How can I set 'default value' for a date time to automatically insert current date time?.

Thanks a lot of your help.

Regards,
Jon
Mac Dude wrote re: Multiple connections to a SQL Server Compact Edition database on a network share Part 2
on 01-11-2008 2:53 AM
Jim Wilson,

My reply took so long cause i use sql server on windows platform.
Jim Wilson wrote re: Multiple connections to a SQL Server Compact Edition database on a network share Part 2
on 01-11-2008 5:42 AM
Mac Dude;

Good to hear from you ...

But back to my original question - what do you disagree with in this post? It's a technical explanation and makes no qualitative judgments or comparisons.

What are you saying he would have done better?

Jim
Paul Diston wrote re: Multiple connections to a SQL Server Compact Edition database on a network share Part 2
on 05-27-2008 8:09 AM
Hi Jim,
I followed the link you posted to the MSDN regarding the Multiuser access to SQL CE databases. I was wondering whether you could answer a few questions I have. 1. In our application we use a connection string to the database that does not specify a MODE, is there a default mode that is used, if so what would that default be? 2. In our application we upgrade a SQL CE 2 database to a SQL CE 3.1 database. Does a default mode get applied to a particular database or is this all defined by the connection string, i.e. would an upgraded SQL CE 2 database have a different/same mode to a freshly created SQL CE 3.1 database?
Thank you, this has been a very interesting and helpful post.
Paul Diston
Jim Wilson wrote re: Multiple connections to a SQL Server Compact Edition database on a network share Part 2
on 05-27-2008 11:08 AM
Paul;

The default mode for SQL Server Compact (SSC) is "Read Write" meaning that multiple applications can open it for both reading and writing. If you want to limit other applications from opening the database, you'll need to specify one of the more restrictive modes explicitly.

The default mode is selected when actually opening the database file; therefore, whether the database file is originally created as SSC 3.1/3.5 or is upgraded from SQL CE 2, the mode will default the same: "Read Write"

I hope that helps.

-Jim

Add a Comment

(required)  
(optional)
(required)  
Remember Me?