Search code examples
c#entity-frameworkef-code-firstsql-server-cerhino3d

Using Entity Framework with Sql Server Compact Edition without App.Config additions


I am developing a plug-in for Rhinoceros 6 and making editions to App.Config file of Rhinoceros seems impossible so far. App.Config of the plug-in project has no effect on App.Config of Rhinoceros.

Below error message appears because I couldn't add providers and parameters to App.Config's <entityFramework> section.

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

I installed EntityFramework.SqlServer.Compact and Microsoft.SqlServer.Compact with NuGet and checked for references, all seems fine.

Below is my code-first dbcontext class :

    public class ModelLocalClipper : DbContext
    { 
        public ModelLocalClipper()
            : base(new SqlCeConnection("Data Source="+ Environment.GetFolderPath(Environment.SpecialFolder.Desktop)+"\\MyDatabase.sdf;Persist Security Info=False;"),
  contextOwnsConnection: true)
        {
            Database.SetInitializer<ModelLocalClipper>(new CreateDatabaseIfNotExists<ModelLocalClipper>());
        }
        
        public DbSet<Scene> Scenes { get; set; }
        public DbSet<LocalProject> LocalProjects { get; set; }
    }

    public class Scene
    {
        public int SceneId { get; set; }
        public string Name { get; set; }

        public int LocalProjectId { get; set; }

        [ForeignKey("LocalProjectId")]
        public virtual LocalProject LocalProject { get; set; }
    }

    public class LocalProject
    {
        public int LocalProjectId { get; set; }
        public string Name { get; set; }

        public virtual ICollection<Scene> Scenes { get; set; }
    }

After searching a while I found this solution and transformed that to use for SQL Server CE as below but it didn't help either

public class SqlCeProviderInvariantName : IProviderInvariantName
{
    public static readonly SqlCeProviderInvariantName Instance = new SqlCeProviderInvariantName();

    private SqlCeProviderInvariantName() { }

    public const string ProviderName = "System.Data.SqlServerCe.4.0";

    public string Name { get { return ProviderName; } }
}

class SqlCeDbProviderFactoryResolver : IDbProviderFactoryResolver
{
    public static readonly SqlCeDbProviderFactoryResolver Instance = new SqlCeDbProviderFactoryResolver();

    private SqlCeDbProviderFactoryResolver() { }

    public DbProviderFactory ResolveProviderFactory(DbConnection connection)
    {
        if (connection is SqlCeConnection) 
            return SqlCeProviderFactory.Instance;

        if (connection is EntityConnection) 
            return EntityProviderFactory.Instance;

        return null;
    }
}

class SqlCeDbDependencyResolver : IDbDependencyResolver
{
        public object GetService(Type type, object key)
        {
            if (type == typeof(IProviderInvariantName)) 
                return SqlCeProviderInvariantName.Instance;

            if (type == typeof(DbProviderFactory)) 
                return SqlCeProviderFactory.Instance;

            if (type == typeof(IDbProviderFactoryResolver)) 
                return SqlCeDbProviderFactoryResolver.Instance;

            return SqlCeProviderServices.Instance.GetService(type);
        }

        public IEnumerable<object> GetServices(Type type, object key)
        {
            var service = GetService(type, key);
            if (service != null) yield return service;
        }
    }

    class SqlCeDbConfiguration : DbConfiguration
    {
        public SqlCeDbConfiguration()
        {
            AddDependencyResolver(new SqlCeDbDependencyResolver());
        }
    }

Versions :

  • RhinoCommon 6.30.20288.16410
  • .NET Framework 4.8
  • Entity Framework 6.4.4
  • SQL Server CE 4.0

With directives of ErikEJ, it worked! For those who want to look into the code here is the repo: https://github.com/Tahirhan/RhinoPluginSqlCECodeFirst

Thanks!


Solution

  • Try this (much simpler) approach, I was able to make that work with a Console app:

    public class SqlCeDbConfiguration : DbConfiguration 
    {
        public SqlCeDbConfiguration()
        {
            SetProviderServices(
                SqlCeProviderServices.ProviderInvariantName,
                SqlCeProviderServices.Instance);
    
            SetDefaultConnectionFactory(
                new SqlCeConnectionFactory(SqlCeProviderServices.ProviderInvariantName));
        }
    }
    

    And then:

    [DbConfigurationType(typeof(SqlCeDbConfiguration))]
    public class ModelSqlCECodeFirst : DbContext