0

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 good.

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 SqlCe 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 -EntityFramework 6.4.4 -SqlServerCe.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!

Tahirhan
  • 302
  • 1
  • 5
  • 14
  • Is the code in the resolver classes called? Is the SQL CE runtime MSI installed on the machine? – ErikEJ Jan 13 '21 at 14:03
  • https://docs.microsoft.com/en-us/dotnet/api/system.data.entity.dbconfiguration.adddependencyresolver?view=entity-framework-6.2.0 – ErikEJ Jan 13 '21 at 14:05
  • https://docs.microsoft.com/en-us/dotnet/api/system.data.entity.dbconfiguration?view=entity-framework-6.2.0 – ErikEJ Jan 13 '21 at 14:06
  • Hi @ErikEJ, I added DbConfiguration derived class that calls resolver to the code but the error persists. And yes SQL CE runtime installed (from this link https://www.microsoft.com/tr-tr/download/details.aspx?id=30709, I guess it is the right package to install?). – Tahirhan Jan 13 '21 at 15:26
  • Yes, right package. – ErikEJ Jan 13 '21 at 16:00
  • Can you create a repro console app that shows the same behaviour, then I can have a look - this is an interesting challenge. – ErikEJ Jan 13 '21 at 16:01
  • I can create a repro project but it will be a rhinoceros plug-in project in order to represent the scenario, and you may need to install rhinoceros 6 to run it. Let me create the project and you can have a look at the code. – Tahirhan Jan 14 '21 at 05:53
  • Here is the link to the repro project https://github.com/Tahirhan/RhinoPluginSqlCECodeFirst – Tahirhan Jan 14 '21 at 06:46

2 Answers2

1

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
ErikEJ
  • 38,654
  • 5
  • 69
  • 109
  • Thanks a lot! I will edit the question and also update the repository. Using "Data Source=|DataDirectory|MyDatabase.sdf;Persist Security Info=False;" produced auth error (because rhino in program files ..) I made an additional change like this "Data Source=|DataDirectory|" + Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\MyDatabase.sdf;Persist Security Info=False;" and it worked. – Tahirhan Jan 14 '21 at 10:49
  • As far as I understand, I need to install runtime for CE to run this project on the client's pc, I thought that I wouldn't need any external installations for CE. – Tahirhan Jan 14 '21 at 11:21
  • If you use the standard package, you do. But you might be able to use my .PrivateDeployment package, if you can figure out how to register the DBProviderFactory in code. – ErikEJ Jan 14 '21 at 20:23
0

As this answer suggested, For SQLite scenario try this DbConfiguration and don't forget to remove "|DataDirectory|" part from connection string

public class SQLiteConfiguration : DbConfiguration
{
    public SQLiteConfiguration()
    {
        SetProviderFactory("System.Data.SQLite", SQLiteFactory.Instance);
        SetProviderFactory("System.Data.SQLite.EF6", SQLiteProviderFactory.Instance);
        SetProviderServices("System.Data.SQLite", (DbProviderServices)SQLiteProviderFactory.Instance.GetService(typeof(DbProviderServices)));
    }
}
Tahirhan
  • 302
  • 1
  • 5
  • 14