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 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!

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Tahirhan
  • 352
  • 1
  • 7
  • 15
  • 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://learn.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://learn.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
  • 40,951
  • 5
  • 75
  • 115
  • 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
  • 352
  • 1
  • 7
  • 15