1

I am having an issue with code-based configuration of Entity Framework 6 and SQL Server CE 4.0. My project is a COM component class library that must work with multiple applications and I cannot know ahead of time which applications will consume the component, so I can't use app.config as a configuration mechanism.

I am attempting to use code-based configuration, as follows. First, my context class:

[DbConfigurationType(typeof(DataConfiguration))]
internal class SlewTargetsDbContext : DbContext
{
    public SlewTargetsDbContext(string connectionString):base(connectionString){  }

    public DbSet<SlewTarget> Targets { get; set; }

    #region Overrides of DbContext
    /// <summary>
    /// Degenerate override prevents any changes from being saved.
    /// </summary>
    public override int SaveChanges() { return 0; }
    #endregion
}

Here is the configuration class:

public class DataConfiguration : DbConfiguration
{
    public DataConfiguration()
    {
        SetExecutionStrategy("System.Data.SqlServerCe.4.0", () => new DefaultExecutionStrategy());
        SetProviderFactory("System.Data.SqlServerCe.4.0", new SqlCeProviderFactory());
        SetProviderServices("System.Data.SqlServerCe.4.0", SqlCeProviderServices.Instance);
    }
}

I have a static method that creates instances of the data contexts, as follows:

public static SlewTargetsDbContext GetTargetDatabase()
{
    var assembly = Assembly.GetExecutingAssembly();
    var assemblyFileName = assembly.Location;
    var path = Path.GetDirectoryName(assemblyFileName);
    var dbFile = Path.Combine(path, "SlewTargets.sdf");
    var builder = new SqlCeConnectionStringBuilder();
    builder.DataSource = dbFile;
    builder.FileMode = "Read Only";
    builder.TempFilePath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);

    var connectionString = builder.ToString();
    var context = new SlewTargetsDbContext(connectionString);

    return context;
}

And finally, I use the data context like this:

Maybe<SlewTarget> LookupTargetFromCoordinates(RightAscension ra, Declination dec)
{
    const double WithinOneMinute = 1.0 / 60.0;    // 1 minute of arc
    var db = CompositionRoot.GetTargetDatabase();

    var targets = from item in db.Targets
                  where item.RightAscension.IsCloseTo(ra.Value, WithinOneMinute) 
                     && item.Declination.IsCloseTo(dec.Value, WithinOneMinute)
                  select item;
    var found = targets.ToList();

    return found.Any() ? new Maybe<SlewTarget>(targets.First()) : Maybe<SlewTarget>.Empty;
}

When I run this code, I get an exception at the point where I create an instance of the data context:

Unable to determine the DbProviderFactory type for connection of type 'System.Data.SqlServerCe.SqlCeConnection'. Make sure that the ADO.NET provider is installed or registered in the application config.

My configuration class explicitly sets the provide factory, however, if I set a breakpoint on that code, it is never hit. So it seems like EF6 is ignoring my configuration. I'm reliant on the attribute on my data context class because I can't use app.config, but that doesn't seem to be working.

I've probably missed something simple but I can't see it. Any ideas?

[Update 2016-02-16 10:30] Removing the [DbConfigurationType] attribute from my data context has helped and now the configuration code is executing. However, now I'm getting this error:

The underlying provider failed on Open.

The InnerException is:

Internal error: Cannot open the shared memory region.

That's a System.Data.SqlServerCe.SqlCeException.

Does that ring any bells?

Tim Long
  • 13,508
  • 19
  • 79
  • 147
  • 1
    look at [this](http://stackoverflow.com/questions/20216147/entity-framework-change-connection-at-runtime), maybe help. – BWA Feb 15 '16 at 21:49
  • @BWA Unfortunately no. That seems to be concerned with connection strings. My connection string is working. I'm beginning to suspect it might be something to do with how I've deployed SQL CE (I'm using the "private" method where you just bundle the files in your own installer"). – Tim Long Feb 16 '16 at 00:22
  • Maybe this: http://stackoverflow.com/questions/29682096/ef6-sql-server-compact-code-based-configuration if you combine with private deployment – ErikEJ Feb 16 '16 at 07:59
  • @ErikEJ Thanks, I had found that but it didn't make any difference. I decided to give up on the private deployment and I authored a bootstrapper that installs SQL CE. That didn't seem to work either, and in desperation I re-read all the documentation and it paid off!! It turns out that I shot myself in the foot by putting the `[DbConfigurationType]` attribute on my data context - you're only supposed to do that if it is in a different assembly to the context class!! Removed it and now my configuration code is being hit. Not there yet, but progress. – Tim Long Feb 16 '16 at 10:29
  • I'm getting an exception now "the underlying provider failed on open" inner exception "Internal error: Cannot open the shared memory region." System.Exception {System.Data.SqlServerCe.SqlCeException} Any thoughts? – Tim Long Feb 16 '16 at 10:32
  • OK it looks like this is a permissions problem now, because I've deployed teh DB into ProgramFiles along with the executables. Even though I've used Read Only mode, SQL CE doesn't like it. Running the app as administrator allows it to work though. It seems like I have to move the database, – Tim Long Feb 16 '16 at 10:53
  • 1
    Success!! I've deployed the database to a location under %ProgramData% and set read/write permissions on the target folder for all users. All working now :) – Tim Long Feb 16 '16 at 13:18

0 Answers0