1

I would like to use my EF Class Library in the console application. I have created a repository in that Class Library that uses DbContext to store data.

My goal is to use this repository in my console app without installing Entity Framework package. Without this package, the app gets me this error:

Unhandled Exception: System.InvalidOperationException: No Entity Framework provider found for the ADO.NET provider with invariant name 'System.Data.SqlClient'. 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.

When I install the EF package, it of course works...

Can someone help me how can I achieve my goal?

MacakM
  • 1,804
  • 3
  • 23
  • 46
  • So you want to use a class that needs Entity Framework for proper functioning, but you don't want to give it Entity Framework? How do you expect this class to function properly? Or are you using only functions of this class that don't use entity framework? – Harald Coppoolse Sep 26 '18 at 13:07
  • I use Entity Framework in Class Library... I want to use this Class Library in my project without need to add NuGet package to this project as well – MacakM Sep 26 '18 at 13:35
  • https://stackoverflow.com/a/29743758/526724 – Bradley Uffner Sep 27 '18 at 03:38

2 Answers2

0

If you have a class library that uses classes from another DLL, for instance EntityFramework.Dll, then in your end product your DLL needs to be able to find this other DLL.

The most easy way to take care of this is to add this other DLL to your references. This will automatically take care that after proper deployment (installation) the other DLL is also copied.

However, quite often you don't want that the users of your DLL also have to refer to the other DLL. Luckily this is not needed as long as you take care that none of the identifiers of the other DLL is in one of your public classes / interfaces

So if your class needs EntityFramework.DLL, and you don't want that users of your class don't have to refer to EntityFramework.DLL, make sure that nothing of the Entity Framework identifiers is public.

The best method is to use interfaces. You could also try to make the items that use Entity Framework internal in your class.

So instead of:

public class DbSchool : DbContext
{
   ...
}

do the following:

public interface IDbSchool
{
    IQueryable<Student> Students {get;}
    IQueryable<Teacher> Teachers {get;}
    IQueryable<ClassRoom> ClassRooms {get;}
    IQueryable<Course> Courses {get;}
}

internal class DbSchool : DbContext, IDbSchool
{
     internal DbSet<Student> Students {get; set;}
     internal DbSet<Teachter> Teachers {get; set;}
     ...

     // Explicit interface implementation of IDbSchool:
     IQueryable<Student> IDbSchool.Students {get => this.Students;}
     IQueryable<Teacher> IDbSchool.Teachers {get => this.Teachers;}
     ...
}

As long as you write code inside your DLL you can use everything from Entity Framework, after all, your DLL refers to it.

The users of your DLL don't refer to Entity Framework, so they can't use identifiers like DbContext and DbSet. However, if they refer to your DLL they can use identifiers as Student, Teacher, Course and of course IDbSchool.

But how does my user create an object of class DbSchool?

Answer: He can't. So you have to create a factory function that returns an IDbSchool:

public static class SchoolFactory
{
    public static IDbSchool CreateSchoolContext(...)
    {
         return new DbSchool(...);
    }
}

Usage:

using (IDbSchool dbSchool = SchoolFactory.CreateSchoolContext(...))
{
      var teachersWithStudents = dbSchoolTeachers
          .Select(teacher => new
          {
              Id = teacher.Id,
              Name = teacher.Name,
              Students = teacher.Students.Select(student => new
              {
                  Id = student.Id,
                  Name = student.Name,
              })
              .ToList(),
          })
          .Where(teacher => teacher.Students.Any());
}

Note: because you want to properly Dispose your DbSchool, your IDbSchool should be derived from IDisposable

public interface IDbSchool, IDisposable {...}
Harald Coppoolse
  • 28,834
  • 7
  • 67
  • 116
  • Thank you, this is theoretically nice, but practically I have a problem that the substitution of DbSet for IQueryable makes the collection less useful (I do not have the same methods). Should I define my own interface that has the same interfaces defined as DbSet? – MacakM Sep 27 '18 at 05:02
  • I showed you that making a facade removes the necessity to reference to the original classes. Just as I made a facade for the IQueryables of your DbSets, you can of course make a Facade for the `IDbSet`. However, you should reconsider this. Is it wise to let your database designs seep through so far outside your original DLL: should users of your DLL really be aware that your archived collections are entity-framework DbSets? Should users of your DLL still know that inside your archive DLL you use enity-framework for your work? – Harald Coppoolse Sep 27 '18 at 14:24
0

The app.config file for your library contains runtime settings. They have no effect because runtime settings have to come from the executable's config file.

Just copy them into your executable project's app.config.

If you wanted to go in the opposite direction, you could create a NuGet package for your library with an install script to modify the target's app.config. That way, no one would have to deal with the internal requirements of the library just to use it in a project.

Tom Blodget
  • 20,260
  • 3
  • 39
  • 72
  • Thank you, I have tried this, but this occurs: `Unhandled Exception: System.AggregateException: One or more errors occurred. ---> System.InvalidOperationException: The Entity Framework provider type 'System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer' registered in the application config file for the ADO.NET provider with invariant name 'System.Data.SqlClient' could not be loaded. Make sure that the assembly-qualified name is used and that the assembly is available to the running application. See http://go.microsoft.com/fwlink/?LinkId=260882 for more information.` – MacakM Sep 27 '18 at 19:47
  • See [How the Runtime Locates Assemblies](https://learn.microsoft.com/en-us/dotnet/framework/deployment/how-the-runtime-locates-assemblies). – Tom Blodget Sep 27 '18 at 20:49