Set EntityFramework Provider from Code

Discussion of open issues, suggestions and bugs regarding ADO.NET provider for SQLite
Post Reply
gte941y
Posts: 6
Joined: Sat 16 Nov 2013 21:17

Set EntityFramework Provider from Code

Post by gte941y » Wed 18 Dec 2013 23:24

I'm developing a library that uses dotConnect for SQLite for code-first EntityFramework capability. In following the code based registration outlined here:http://blog.devart.com/entity-framework ... force.html I was able to get everything working within a test harness designed to test my library. Unfortunately, my current approach requires that I include the following sections in the main App.config file:

Code: Select all

<configSections>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework,  Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  </configSections>
  <entityFramework>
    <providers>
      <provider invariantName="Devart.Data.SQLite" type="Devart.Data.SQLite.Entity.SQLiteEntityProviderServices, Devart.Data.SQLite.Entity, Version=5.1.55.6, Culture=neutral, PublicKeyToken=09af7300eec23701" />
    </providers>
  </entityFramework>
This is a problem as my library is being developed for a third party tool and I would rather not modify the App.config file of the parent application. Without this data in the App.config file I receive the following error:
"No Entity Framework provider found for the ADO.NET provider with invariant name 'Devart.Data.SQLite'. Make sure the provider is registered in the 'entityFramework' section of the application config file."

Is there a way to configure the entity framework provider outside of the App.config file?

For a little more background, my DbConfiguration class is simply:

Code: Select all

public class SQLiteConfiguration:DbConfiguration
    {
        public SQLiteConfiguration()
        {
            SetDefaultConnectionFactory(new SQLiteConnectionFactory());
            SetProviderFactory("Devart.Data.SQLite",new SQLiteProviderFactory());
        }
    }
And the SQLiteConnectionFactory is a direct copy from the crmDemo that you provide.

Thanks!

Shalex
Site Admin
Posts: 9543
Joined: Thu 14 Aug 2008 12:44

Re: Set EntityFramework Provider from Code

Post by Shalex » Thu 19 Dec 2013 17:25

1. Registering EF6-provider via code:

Code: Select all

public class MyContext: ObjectContext { 
  static MyContext() {
    DbConfiguration.SetConfiguration(new Devart.Data.SQLite.Entity.SQLiteEntityProviderServicesConfiguration());
  } 
  // ...
}
2.
gte941y wrote:This is a problem as my library is being developed for a third party tool and I would rather not modify the App.config file of the parent application.
Additionally, .NET provider should be registered in the DbProviderFactories section: http://www.devart.com/dotconnect/sqlite ... yment.html. The dotConnect for SQLite installation puts this entry in machine.config but your tool will be run on the workstation without dotConnect for SQLite installed, so you should implement the corresponding registration via code: http://stackoverflow.com/questions/1117 ... app-config (this is an example, but you can use the same scenario for Devart.Data.SQLite).

gte941y
Posts: 6
Joined: Sat 16 Nov 2013 21:17

Re: Set EntityFramework Provider from Code

Post by gte941y » Mon 23 Dec 2013 05:13

Thank you for the reply, I've tried to implement the changes you suggested but unfortunately I'm still getting the same errors whenever I try to access any data from the Entity Framework.
1. The class "Devart.Data.SQLite.Entity.SQLiteEntityProviderServicesConfiguration()" that you referenced below doesn't appear to be of the proper type for the SetConfiguration function. Was that a typo? Did you intend to reference another class? Regardless, I did add the SetConfiguration command to the ctor of my DbContext implementation but passed in the aforementioned SQLiteConfiguration class. This didn't appear to help.
2. I've added the following code to inject the Devart.SQLite libraries into the DbProviderFactories:

Code: Select all

var dataSet = System.Configuration.ConfigurationManager.GetSection("system.data") as DataSet;
dataSet.Tables[0].Rows.Add("SQLite Data Provider"
                    , ".Net Framework Data Provider for SQLite"
                    , "Devart.Data.SQLite"
                    ,
                    "Devart.Data.SQLite.Entity.SQLiteEntityProviderServices, Devart.Data.SQLite.Entity, Version=5.1.55.6, Culture=neutral, PublicKeyToken=09af7300eec23701");
But still no joy.

I've hacked up a very basic testbed based around the stereotypical school(student, class, enrollment) example to verify that the behavior wasn't particular to my project and I'm getting the same results (no surprise given that its the same developer :D). I'm happy to pass this example to you if that would help.

===========
Edit
===========

I went ahead and uploaded the source to my github page, you should be able to pull from here:[email protected]:gte941y/DevartTest.git


Thanks!

Shalex
Site Admin
Posts: 9543
Joined: Thu 14 Aug 2008 12:44

Re: Set EntityFramework Provider from Code

Post by Shalex » Wed 25 Dec 2013 12:32

Please replace the content of the Model \ SchoolContext.cs file in your project with the following:

Code: Select all

using System.Configuration;
using System.Data;
using System.Data.Entity;
using Devart.Data.SQLite;
using System.Data.Common;

namespace DevartEFTest.Model
{
    public class SchoolContext : DbContext
    {
        static SchoolContext() {
            DbConfiguration.SetConfiguration(new SQLiteConfiguration());
        }
        
        public SchoolContext(string databasePath)
            : base(GetConnection(databasePath), true) {          
        }

        private static DbConnection GetConnection(string databasePath) {

            InitializeDb();

            SQLiteConnectionStringBuilder connSb = new SQLiteConnectionStringBuilder() {
                DataSource = databasePath,
                FailIfMissing = false,
                Pooling = true
            };

            return new SQLiteConnection(connSb.ConnectionString);
        }

        //Each DbSet property creates an entity set which typically corresponds to a database table
        //an entity corresponds to a row in the table
        public DbSet<StudentModel> Students { get; set; }
        public DbSet<EnrollmentModel> Enrollments { get; set; }
        public DbSet<CourseModel> Courses { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            Database.SetInitializer<SchoolContext>(new SchoolInitializer());
        }

        private static void InitializeDb()
        {
            bool DevartProviderRegistered = false;
            var dataSet = System.Configuration.ConfigurationManager.GetSection("system.data") as DataSet;
            foreach (DataRow dr in dataSet.Tables[0].Rows)
            {
                if ((string)dr[2] == "Devart.Data.SQLite")
                {
                    DevartProviderRegistered = true;
                }
            }

            if (!DevartProviderRegistered)
            {
                dataSet.Tables[0].Rows.Add("dotConnect for SQLite"
                    , "Devart dotConnect for SQLite"
                    , "Devart.Data.SQLite"
                    ,
                    "Devart.Data.SQLite.SQLiteProviderFactory, Devart.Data.SQLite, Version=5.1.55.0, Culture=neutral, PublicKeyToken=09af7300eec23701");

            }
        }
    }
}
Please try this and notify us about the result. If you receive any exception, specify the exact text of the error with its call stack.

gte941y
Posts: 6
Joined: Sat 16 Nov 2013 21:17

Re: Set EntityFramework Provider from Code

Post by gte941y » Thu 26 Dec 2013 16:18

With the addition of your code I'm still getting the same error:
No Entity Framework provider found for the ADO.NET provider with invariant name 'Devart.Data.SQLite'. Make sure the provider is registered in the 'entityFramework' section of the application config file. See http://go.microsoft.com/fwlink/?LinkId=260882 for more information.

Here's the stacktrace:

Code: Select all

   at DevartEFTest.StudentsViewModel..ctor(String databasePath) in c:\Users\user\My Repos\DevartTest\DevartEFTest\DevartEFTest\StudentsViewModel.cs:line 39
   at DevartEFTest.MainWindow.LaunchStudents_OnClick(Object sender, RoutedEventArgs e) in c:\Users\user\My Repos\DevartTest\DevartEFTest\DevartEFTest\MainWindow.xaml.cs:line 40
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)
   at System.Windows.Controls.Primitives.ButtonBase.OnClick()
   at System.Windows.Controls.Button.OnClick()
   at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
   at System.Windows.UIElement.OnMouseLeftButtonUpThunk(Object sender, MouseButtonEventArgs e)
   at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
   at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent)
   at System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e)
   at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
   at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args)
   at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
   at System.Windows.Input.InputManager.ProcessStagingArea()
   at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
   at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
   at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
   at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.Run()
   at System.Windows.Application.RunDispatcher(Object ignore)
   at System.Windows.Application.RunInternal(Window window)
   at System.Windows.Application.Run(Window window)
   at System.Windows.Application.Run()
   at DevartEFTest.App.Main() in c:\Users\user\My Repos\DevartTest\DevartEFTest\DevartEFTest\obj\Debug\App.g.cs:line 0
   at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

MariiaI
Devart Team
Posts: 1472
Joined: Mon 13 Feb 2012 08:17

Re: Set EntityFramework Provider from Code

Post by MariiaI » Fri 27 Dec 2013 10:33

Please add the following code to the SQLiteConfiguration.cs file:

Code: Select all

SetProviderServices("Devart.Data.SQLite", SQLiteEntityProviderServices.Instance);
Also, we recommend you to rewrite this code in the InitializeDb() method:

Code: Select all

 if (!DevartProviderRegistered)
            {
                dataSet.Tables[0].Rows.Add("dotConnect for SQLite"
                    , "Devart dotConnect for SQLite"
                    , "Devart.Data.SQLite"
                    ,
                    "Devart.Data.SQLite.SQLiteProviderFactory, Devart.Data.SQLite, Version=" + Devart.Data.SQLite.ProductInfo.Version + ", 
Culture=neutral, PublicKeyToken=09af7300eec23701");
            }
I.e. use Devart.Data.SQLite.ProductInfo.Version instead of writing version manually, so that after upgrading your dotConnect for SQLite there was no version inconsistency.

We are sending you a modified test project to the e-mail address you have provided in your forum profile. Please check that the letter is not blocked by your mail filter

Please tell us about the results.

gte941y
Posts: 6
Joined: Sat 16 Nov 2013 21:17

Re: Set EntityFramework Provider from Code

Post by gte941y » Fri 27 Dec 2013 14:45

That seems to have solved the problem. Thank you much!

Post Reply