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?