Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Entity framework work for release 2.1.0 #110

Merged
merged 8 commits into from
Dec 6, 2013
Merged

Entity framework work for release 2.1.0 #110

merged 8 commits into from
Dec 6, 2013

Conversation

roji
Copy link
Member

@roji roji commented Dec 1, 2013

This is still WIP, please do not merge.

Continued discussion from #109 (comment)

@roji
Copy link
Member Author

roji commented Dec 1, 2013

I just had an idea for another approach to the nuget/EF problem...

Would it be possible to split off the entities framework-dependent code into another DLL altogether? If so, we could package one Npgsql nuget without any EF stuff, and simple two add-on packages - EntityFramework (for EF6) and EntityFrameworkLegacy (for pre-EF6). If possible, this definitely seems like the cleanest approach here.

I'll take a look at this, but I'll need the help of someone who actually knows EF a little...

@kenjiuno
Copy link
Contributor

kenjiuno commented Dec 1, 2013

Hi roji.

I'll help you as far as I can.

btw Here is my usage:

I'm rewriting my company's obsolete ERP system built on 4th Dimension. It has many tables. So I prefer database-first approach in EF. It is the reason I selected EF. (I also tried DbLinq, but it misses some important features)

My development environment:

  • Visual Studio Express 2012 for Desktop (C# .NET4.5)
  • WPF application project.
  • Npgsql(ADO.net + legacyEF) + NpgsqlEF6(only EFv6)

My way to deploy Npgsqls:

  • Npgsql.dll into GAC. Because all of VisualStudio/EdmGen/application use it.
    • I attach my own StrongNameKey.
    • I modify machine.config to declare Npgsql in DbProviderFactories.
  • NpgsqlEF6.dll to workdir. Because only application uses it.
    • I modify App.config to declare provider.

My tools for EF:

  • EdmGen
    • Code and schema generator
    • Shipped with .NET3.5/4.0/4.5
    • Windows user will find it at C:\Windows\Microsoft.NET\Framework\v4.0.30319\EdmGen.exe
    • Uses legacyEF
  • EdmGen2
  • EdmGen06
    • My own version
    • Having StoredProcedures/Functions support
    • Still uses legacyEF
  • EF 6.x DbContext Generator

Note:

It is the research result obtained in last month.

Sorry. I'll discuss about approach to the nuget/EF packaging problem, at next time.

@roji
Copy link
Member Author

roji commented Dec 1, 2013

@kenjiuno, thanks for this info. I know you did a lot of testing/work on getting EF to work, I should have followed that more.

Some quick comments/questions:

  • Are you saying there is no way to get VS to recognize/load Npgsql.dll without installing it into the GAC? I think it's pretty rare/last-resort to do this in general.
  • You mention that you don't install NpgsqlEF6, because only the application uses it. Is this a change from legacy EF, or some difference in the way you specifically use EF?
  • From very quick reading, I think VS2013 is supposed to come with all the tooling necessary for EF6 (this is new in 2013).
  • Are all the tools you mention above (EdmGen, EdmGen2, EdmGen6...) not ported to EF6? Aren't there EF6 alternatives for them?

In general, my approach to EF was like to any other .NET dependent library: install it via nuget and it gets referenced in your project (no GAC or anything). I understand this approach may be insufficient for EF (because of the special relationship to VS), if this is truly the case I can try to look for a "standard" nuget way to get a DLL into the GAC?

@franciscojunior
Copy link
Member

This is what I wrote in the #109 before seeing Shay's message to continue the discussion here:

"I liked your strategy of the three packages. Those three packages would cover all the possible scenarios for Npgsql users.

I also think we should share this question to devel-list."

And by seeing your new idea of using add-ons, I think this would be very good too. I just don't know how much complicated it would be to get the EF code split. Maybe we would need to make those EF assemblies a friend assembly of Npgsql so they can access Npgsql internals.

But I think that having a non EF Npgsql, a 4.3EF and a current 6.0EF would cover all the scenarios a developer would need, wouldn't they?

I think the problem with edmgen, from the little experience I have, is that it looks in the GAC and in the machine.config the configuration to use the providers. I couldn't find a switch to make edmgen works otherwise. I didn't try to create a custom edmgen.exe.config file in my current folder and see if it loads the configuration from there though. If it does, I think we could start to ship custom edmgen.exe.config files preconfigured for Npgsql.

The only way I could get edmgen using an Npgsql version without installing in GAC was when I put it as the executable to debug the Npgsql project. But of course this isn't the ideal situation.

I'd bet in the edmgen.exe.config file or something like that to make edmgen look for Npgsql in another place other than the GAC.

I hope what I said makes any sense.

@kenjiuno
Copy link
Contributor

kenjiuno commented Dec 1, 2013

Hi.

In general, my approach to EF was like to any other .NET dependent library: install it via nuget and it gets referenced in your project (no GAC or anything). I understand this approach may be insufficient for EF (because of the special relationship to VS), if this is truly the case I can try to look for a "standard" nuget way to get a DLL into the GAC?

I'm sorry. I have confused you too much.

Npgsql can be distributed in the nuget's standard way. I'll welcome it!

I forgot to say: why Npgsql and NpgsqlEF6 should be separated?

It is problem about assembly's qualified name.

For example: the following assembly is recent Npgsql's assembly sign.

Npgsql, Version=2.0.12.91, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7

It may be ...

  • Pure Npgsql provider without EF.
  • Npgsql with legacyEF.
  • Npgsql with EFv6.
  • Npgsql with VS Designer support.

We cannot identify it easily...

This is first problem.

Next problem is about GAC.

About VS Designer support version of Npgsql, it is said Npgsql should be put into GAC. http://fxjr.blogspot.jp/2011/05/npgsql-design-time-support-preview.html

And then, if your Npgsql assembly has same assembly signature like

Npgsql, Version=2.0.12.91, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7

your version won't be loaded.

because MS's .NET runtime searches GAC at first, not our working folder.

How the Runtime Locates Assemblies
http://msdn.microsoft.com/en-us/library/yx7xezcf(v=vs.110).aspx

It may cause unpredictable problem in the future.

So I thought the following combination will be better, if your nuget package shall be official release point.

  • Npgsql.dll ← ADO.net + legacyEF
  • NpgsqlEF6.dll ← only EFv6

I don't mind that you will prepare 3 nuget packages.

My idea is just reminder, if you use same assembly signature in all 3 packages.


If you need answer for each question, please go down the following line :)


Hi.

Are you saying there is no way to get VS to recognize/load Npgsql.dll without installing it into the GAC? I think it's pretty rare/last-resort to do this in general.

I think Yes about DDEX support.

DDEX requests InvariantName (Npgsql) to obtain DbProviderFactory class. http://msdn.microsoft.com/ja-jp/library/bb163767(v=vs.90).aspx

It means we have to install Npgsql.dll into GAC, and then edit machine.config for DbProviderFactories.

Otherwise,

If you use VisualStudio 2012 for Desktop, edit WDExpress.exe.config instead, and then copy Npgsql.dll to Visual Studio install folder which they can find it.

But, there is no problem about nuget support, nuget can install the assembly into VS project easily.

You mention that you don't install NpgsqlEF6, because only the application uses it. Is this a change from legacy EF, or some difference in the way you specifically use EF?

Yes, there is a little difference in way to get interface.

http://entityframework.codeplex.com/wikipage?title=Rebuilding%20EF%20providers%20for%20EF6

About legacyEF, it is said like tightly coupled the EF provider to the DbProviderFactory.

  providerName = "Npgsql";

  DbProviderFactory fac = System.Data.Common.DbProviderFactories.GetFactory(providerName);
  ...
  DbProviderServices providerServices = ((IServiceProvider)fac).GetService(typeof(DbProviderServices)) as DbProviderServices;
  ...

And, we will add provider description in either App.config or machine.config so that ADO.net can find it.

<configuration>
  <system.data>
    <DbProviderFactories>
      <add name="Npgsql Data Provider" 
           invariant="Npgsql" 
           description=".Net Data Provider for PostgreSQL" 
           type="Npgsql.NpgsqlFactory, Npgsql, Version=2.0.12.91, Culture=neutral, PublicKeyToken=da0cf53beacd9ab5" 
           support="FF" 
           />
    </DbProviderFactories>
  </system.data>
</configuration>

About EFv6, provider element is needed to add manually. nuget may need support for it.

<configuration>
  <configSections>
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false"/>
    <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
  </configSections>
  <entityFramework>
    <providers>
      <provider invariantName="Npgsql" 
                type="NpgsqlEF6.NpgsqlServices, NpgsqlEF6, Version=2.0.12.91, Culture=neutral, PublicKeyToken=da0cf53beacd9ab5"
                />
    </providers>
  </entityFramework>
</configuration>

There are two Npgsql.

  • ADO.net's invariant="Npgsql" is for providing DbProviderFactory.
    • DbProviderFactory.GetService may return DbProviderServices (System.Data.Common) if it supports legacyEF.
  • EFv6's invariantName="Npgsql" is for providing DbProviderServices (System.Data.Entity.Core.Common).

Continue with EFv6, connectionString is written by EntityDataModel designer or us.

<configuration>
  <connectionStrings>
    <add name="Model1Container" 
         connectionString="metadata=res://*/Model1.csdl|res://*/Model1.ssdl|res://*/Model1.msl;
                           provider=Npgsql;
                           provider connection string=&quot;port=5432;timeout=15;pooling=True;minpoolsize=1;maxpoolsize=20;commandtimeout=20;compatible=2.0.12.91;host=127.0.0.1;user id=npgsql_tests;database=ef_db_first_sample;password=npgsql_tests&quot;" 
         providerName="System.Data.EntityClient" 
         />
  </connectionStrings>
</configuration>

Finally, generated context class refers connectionString by its name.

    public partial class Model1Container : DbContext
    {
        public Model1Container()
            : base("name=Model1Container")
        {
        }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            throw new UnintentionalCodeFirstException();
        }

        public DbSet<Blog> Blogs { get; set; }
        public DbSet<Post> Posts { get; set; }
    }

From very quick reading, I think VS2013 is supposed to come with all the tooling necessary for EF6 (this is new in 2013).

Probably yes.

It is said VS2010 project can apply EF6 by nuget too. http://blogs.msdn.com/b/daisukei/archive/2012/08/17/entity-framework-5-ef5-ef-6.aspx

VS2012 can do it too.

Are all the tools you mention above (EdmGen, EdmGen2, EdmGen6...) not ported to EF6? Aren't there EF6 alternatives for them?

Sorry, I find yet no tooling targeting EFv6 directly.

The reason why it can't be done is: EFv6 provider is not registered anywhere inside Windows.

If you install EntityFramework 6.0.1 from nuget, nuget writes SQL Server's EFv6 provider information into App.config.

<provider invariantName="System.Data.SqlClient" 
          type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" 
          />

If we prepare our own EdmGen for EFv6, we will have to attach Npgsql EFv6 Provider within EdmGen package.

btw EdmGen is provider independent. Any of SQLServer/Npgsql/Firebird/SQLite.net/etc can be applied if they support legacyEF.

@roji
Copy link
Member Author

roji commented Dec 1, 2013

Thanks for the input.

Let me try and play around with the add-on architecture, it may not be that difficult to split the EF-related code out, and that would be a very clean solution to the problem. We would then have an entirely separate project (NpgsqlEntityFramework), from which we'd generate two nuget packages - one for legacyEF and one for EF6.

Then, whether you install the DLL into the GAC or not, based on whether you need DDEX/EdmGen/whatever is up to you...

PS I sent an email to the devel list linking this discussion to get additional feedback.

@kenjiuno
Copy link
Contributor

kenjiuno commented Dec 1, 2013

Hi.
Thanks for reply.

I see it is not good idea to put Npgsql into GAC in usual operation.

Just FYI.

It fires exception, if we have same provider name (Npgsql) in both App.config and machine.config.

  <system.data>
    <DbProviderFactories>
      <add name="Npgsql Data Provider" invariant="Npgsql" .../>
    </DbProviderFactories>
  </system.data>
  • Unhandled Exception: System.Configuration.ConfigurationErrorsException: An error occurred creating the configuration section handler for system.data: Column 'InvariantName' is constrained to be unique. Value 'Npgsql' is already present. (H:\Proj\TestNpgsqlEF\DDExNpgsql\bin\Debug\DDExNpgsql.exe.Config line 10) ---> System.Data.ConstraintException: Column 'InvariantName' is constrained to be unique. Value 'Npgsql' is already present.
  • We will have to remove one from machine.config in this case.

@roji
Copy link
Member Author

roji commented Dec 1, 2013

OK, I've looked at the situation and I think I may have an idea how to solve it in the best way. I'm not talking about GAC, machine.config vs. App.config issues, only on how the package and use Npgsql and its EF components and deliver them to users (the GAC / machine.config discussion is also very important but I want to concentrate...).

Background:

  • Legacy EF requires that DbProviderlFactory (which must be part of the Npgsql core package as it serves other needs) make the EF-only DbProviderServices available via GetService(). This is the only reference from "core" Npgsql code to EF-specific code, all the rest (NpgsqlServices, NpgsqlProviderManifest, SQLGenerators*) is purely EF-specific and can theoretically be split off.
  • In EF6 DbProviderFactory has been decoupled from DbProviderServices, so NpgsqlServices is no longer accessed via NpgsqlFactory.

This allow us to do the following:

  • Compile one Npgsql.dll that contains legacy EF support. This means we reference System.Data.Entity, and include all the EF-specific stuff, defining ENTITIES but not ENTITIES6
  • In addition, we distribute a second package, Npgsql.EntityFramework6. This package depends on Npgsql and on the EF6 nuget. It also compiles all the EF-specific stuff, defining both ENTITIES and ENTITIES6.
  • Legacy EF users call GetServices() on NpgsqlFactory, which gives the NpgsqlServices for legacy EF. EF6 users bypass this and reference the NpgsqlServices directly from Npgsql.EntityFramework6.dll, as is standard in EF6: http://entityframework.codeplex.com/wikipage?title=Rebuilding%20EF%20providers%20for%20EF6. Everyone gets exactly what they need.
  • This leaves only mono. mono does not have the legacy EF assemblies. However, as long as the NpgsqlFactory's GetService() method isn't actually called, the method won't be jitted and those assemblies will never be looked for (I have tested this). Using EF6 is exactly like on regular .NET.

The advantage of the above is exactly one Npgsql nuget package, and exactly one Npgsql.EntityFramework6 add-on package. No more confusion on which version I have, does it support EF6 or not, etc.

It does mean we need a new project, Npgsql.EntityFramework6, in the solution for the EF6 add-on. Npgsql and Npgsql.EntityFramework6 would share some of the same .cs source files (the EF-specific ones), but the EF6 project would compile with ENTITIES6.

Hope that made sense and wasn't too long. Comments?

@franciscojunior
Copy link
Member

Hi all,
I'm in my cell phone and just wanted to add the following :
regarding the machine.config error about the provider registration, there
is a pull request which added an app.config file where it added a directive
to remove the pre registered Npgsql provider from the machine.config and
then added the app specific registration. This way, even if there is an
Npgsql provider registered in the machine configuration file it won't
interfere with the application.

I don't remember exactly the syntax but it was something like:

Dbproviderfactories
Remove invariant name = npgsql
Add ....
Dbproviderfactories

Something like that.

I hope it helps
Em 01/12/2013 14:27, "kenjiuno" notifications@github.com escreveu:

Hi.
Thanks for reply.

I see it is not good idea to put Npgsql into GAC in usual operation.

Just FYI.

It fires exception, if we have same provider name (Npgsql) in both
App.config and machine.config.

<system.data>

<add name="Npgsql Data Provider" invariant="Npgsql" .../>

</system.data>

Unhandled Exception:
System.Configuration.ConfigurationErrorsException: An error occurred
creating the configuration section handler for system.data: Column
'InvariantName' is constrained to be unique. Value 'Npgsql' is already
present. (H:\Proj\TestNpgsqlEF\DDExNpgsql\bin\Debug\DDExNpgsql.exe.Config
line 10) ---> System.Data.ConstraintException: Column 'InvariantName' is
constrained to be unique. Value 'Npgsql' is already present.

We will have to remove one from machine.config in this case.


Reply to this email directly or view it on GitHubhttps://github.com//pull/110#issuecomment-29576792
.

@kenjiuno
Copy link
Contributor

kenjiuno commented Dec 2, 2013

Hi.

I don't remember exactly the syntax but it was something like:

Great! It helps to resolve machine.config vs. App.config issues.

I have tested some patterns with following App.config.

    <DbProviderFactories>
      <remove invariant="Npgsql" />
      <add name="Npgsql Data Provider" invariant="Npgsql" ... />
    </DbProviderFactories>

Tests:

  • machine.config has Npgsql with another signature. App.config has <remove> and <add>.
  • machine.config has Npgsql with same signature. App.config has <remove> and <add>.
  • machine.config has no Npgsql. App.config has <remove> and <add>.

Result: all passed.

Test code:

using System;
using System.Data.Common;

namespace ConsoleApplication30 {
    class Program {
        static void Main(string[] args) {
            var fac = DbProviderFactories.GetFactory("Npgsql");
            Console.WriteLine(fac.GetType().AssemblyQualifiedName);
        }
    }
}

@kenjiuno
Copy link
Contributor

kenjiuno commented Dec 2, 2013

Hi.

Hope that made sense and wasn't too long. Comments?

I think it is the realistic and the best idea for now. I agree with your idea!

I think the problem with edmgen, from the little experience I have, is that it looks in the GAC and in the machine.config the configuration to use the providers. I couldn't find a switch to make edmgen works otherwise. I didn't try to create a custom edmgen.exe.config file in my current folder and see if it loads the configuration from there though. If it does, I think we could start to ship custom edmgen.exe.config files preconfigured for Npgsql.

I think shipping edmgen.exe.config is good idea.

The developers can copy edmgen.exe from their .NET directory easily.

And then, we can simply call edmgen.exe without: putting Npgsql/Mono.Security into GAC, and editing machine.config

@roji
Copy link
Member Author

roji commented Dec 2, 2013

One more optimization on my above proposal...

Rather than compile the EF code into Npgsql.dll for legacy mode, and relying on mono not trying to jit it, I propose to simply compile an Npgsql.EntityFrameworkLegacy.dll for pre-EF6. The NpgsqlFactory, which has to expose the legacy-EF NpgsqlServices, would load this DLL with runtime reflection (Assembly.Load()), and throw an exception if not found.

So to sum it up: One Npgsql nuget, one Npgsql.EntityFrameworkLegacy nuget (for pre-EF6 users), one Npgsql.EntityFramework nuget (for EF6 and on).

I'll probably work on this later today... Let me know if you guys have any input.

@kenjiuno
Copy link
Contributor

kenjiuno commented Dec 2, 2013

Hi.

The NpgsqlFactory, which has to expose the legacy-EF NpgsqlServices, would load this DLL with runtime reflection (Assembly.Load()), and throw an exception if not found.

Ok.
If you expose legacy-EF, probably it will be safe to try Assembly.Load("Npgsql.EntityFrameworkLegacy") because Google/Bing has no search result about Npgsql.EntityFrameworkLegacy for now. :)

@roji
Copy link
Member Author

roji commented Dec 2, 2013

I'm actually planning to do this: Assembly.Load("Npgsql.EntityFrameworkLegacy, PublicKeyToken=5d8b90d52f46fda7")

This ensures we only get our own proper DLL...

@kenjiuno
Copy link
Contributor

kenjiuno commented Dec 2, 2013

Hi.
It will work as you expect.

I tested with Npgsql: Assembly.Load("Npgsql, PublicKeyToken=5d8b90d52f46fda7")
It loaded Npgsql at work dir.
It rejected Npgsql at work dir with different signature.

It is good idea!

@franciscojunior
Copy link
Member

Rather than compile the EF code into Npgsql.dll for legacy mode, and relying on mono not trying to jit it, I propose to simply compile an Npgsql.EntityFrameworkLegacy.dll for pre-EF6. The NpgsqlFactory, which has to expose the legacy-EF NpgsqlServices, would load this DLL with runtime reflection (Assembly.Load()), and throw an exception if not found.

So to sum it up: One Npgsql nuget, one Npgsql.EntityFrameworkLegacy nuget (for pre-EF6 users), one Npgsql.EntityFramework nuget (for EF6 and on).

+1 for this. This way if a user doesn't need the legacy EF support she doesn't even need to worry about possible jit or dependency problems.

@roji
Copy link
Member Author

roji commented Dec 2, 2013

OK, I've been hacking at this for a while and I think it's close to finished (but not quite). Unfortunately personal life calls, darn.

@kenjiuno, @franciscojunior and anyone else, please review this latest commit and left me know what you think. It looks big and scary but it really isn't - just a reorganization of the code into three cleanly-separated projects.

Note that it's still WIP; the legacy EF mode still isn't done (I have a bit of reflection code to write). But most of the rest (specifically the EF6 mode) should work fine.

It's really important for me to get feedback on this, both because I don't know EF as well as I should and because it's an important project structure change.

Good night...

@kenjiuno
Copy link
Contributor

kenjiuno commented Dec 3, 2013

Hi.

Thanks. I have tested your commit, and here is patch kenjiuno/Npgsql@bedf593. It is for getting myApp/EdmGen/EdmGen06 working in my development computer.

EDIT: fixed commit link

@franciscojunior
Copy link
Member

I also tested it here and the project restructuring seems very nice.

I noticed that you edited the 2013 project with vs. Net 2012 because it
changed the header of the file to vs 2012. :-)

I could only test the nunit tests. I didn't test yet the entity framework
as I also don't have much experience with it besides the test cases people
posted in the github.

Excellent work, Shay! I'll test more tomorrow.

Thanks Kenji for testing that too.
Em 02/12/2013 23:58, "kenjiuno" notifications@github.com escreveu:

Hi.

Thanks. I have tested your commit, and here is patch bedf593bedf593.
It is for getting myApp/EdmGen/EdmGen06 working in my development computer.


Reply to this email directly or view it on GitHubhttps://github.com//pull/110#issuecomment-29677229
.

roji and others added 5 commits December 4, 2013 00:03
- Reorganized the code into three projects/packages:
  1) The Npgsql "core", fully functional ADO.NET and no EF
  2) Npgsql.EntityFramework, an add-on for users of EF6 and above
  3) Npgsql.EntityFrameworkLegacy, an add-on for users of EF5 and below
- All EF-related code has been split off from Npgsql and into
  the Npgsql.EntityFramework directory
- The same EF code is built via two projects: Npgsql.EntityFramework
  (defining ENTITIES6 for the new EF6), and Npgsql.EntityFrameworkLegacy
  (not defining it for pre-EF6).

Still to be done:
- Npgsql.NpgsqlFactory doesn't yet do the reflection work to return the
  pre-EF6 NpgsqlServices
- Only the 2013 sln is up to date
- nuspecs
Tested on:
- Windows 7 Home Premium SP1 64-bit
- 3 assemblies got into gac.
  Debug-net45\Npgsql.dll
  Debug-net45\Npgsql.EntityFramework.dll
  Legacy-Debug-net45\Npgsql.EntityFrameworkLegacy.dll
- machine.config modified.
- my EFv6 app's App.config modified.
- Tightened some details in the reflection loading of EntityFrameworkLegacy
  (thanks kenjiuno)
- Did nuspecs entity framework projects
- Corrected SLNs for 2012, 2010
@roji
Copy link
Member Author

roji commented Dec 3, 2013

OK, I think it's pretty much ready. @kenjiuno, I cherry-picked your commit and added some last fixing.

@kenjiuno and @franciscojunior, can I ask you guys for one more checkup, both for the EF6 and legacy EF scenarios? If it all goes well I think we can merge this.

Rewrote assembly and type resolving better.
@kenjiuno
Copy link
Contributor

kenjiuno commented Dec 4, 2013

Hi.

Thanks, I have tested the new code.

It raises FileNotFoundException inside NpgsqlFactory.GetService

  • Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'System.Data.Entity, PublicKeyToken=b77a5c561934e089' or one of its dependencies. 指定されたファイルが見つかりません。

It seems gac dll needs full qualified typename to be loaded.

I have committed quick fix kenjiuno/Npgsql@0265ccd

And, I have prepared test toolkit for our easier testing.

EdmGen06_20131204.7z https://drive.google.com/file/d/0BzIsP2o582nbZS03Vm9EbmVibjg/edit?usp=sharing

EdmGen06 is my alternative one to EdmGen written by MS.

It can build schema edmx(ssdl/msl/csdl) files from database (e.g. your PostgreSQL server instance).

At that tool, you can try both legacyEF and EFv6 supports, directly. Almost all configurations are already done.

for legacyEF

  • replace Npgsql.dll and Npgsql.EntityFrameworkLegacy.dll with yours.
  • edit GenLegacyEF.bat to correct Npgsql connection string.
  • call GenLegacyEF.bat

for EFv6

  • move to EFv6 directory.
  • replace Npgsql.dll and Npgsql.EntityFramework.dll with yours.
  • edit GenEFv6.bat to correct Npgsql connection string.
  • call GenEFv6.bat

If you succeed, you will get npgsql_tests.edmx. It is useful to be used with code generator such as EF 6.x DbContext Generator.

Note: EdmGen06 is still development stage (pre-alpha)

Source code: https://github.com/kenjiuno/EdmGen06/releases

@franciscojunior
Copy link
Member

Excellent, Kenji!

I think your tool EdmGen06 will be very helpful to Npgsql users :)

Shay, sorry I couldn't reply before. I'll make some tests this afternoon and will report you back if I find any problem.

@roji
Copy link
Member Author

roji commented Dec 4, 2013

@kenjiuno, thanks for continuing to work on this. Two things about your proposed commit:

  • I'm surprised System.Data.Entity isn't loaded unless you specify a full assembly name, including the version. Specifying 4.0.0 limits legacy EF users to exactly version 4.0.0, but I think we want to support other legacy EF versions, no? Let me investigate the GAC loading issue a bit on my side too.
  • For Npgsql.EntityFrameworkLegacy, I think it's the exact opposite. We should only load the DLL with the exact version of the the Npgsql that's running. This is what you do in the first load attempt, but later you fall back to loading any Npgsql.EntityFrameworkLegacy, regardless of version (and even PublicKeyToken). This means it's possible for Npgsql version 3.0.0 to load Npgsql.EntityFrameworkLegacy 2.0.0 by accident, and since these two DLLs are closely coupled (there are internal calls between them) that could break. Is it OK for you if we remove the fallback loading?

@kenjiuno
Copy link
Contributor

kenjiuno commented Dec 5, 2013

Hi.
Thanks for reply!

Specifying 4.0.0 limits legacy EF users to exactly version 4.0.0, but I think we want to support other legacy EF versions, no?

I agree. I forgot it yesterday ;)

I'll consider the possible combinations of .NET and EF, as possible as I can. This is the list of possible ones I think, but I don't check all of them.

For Npgsql.EntityFrameworkLegacy, I think it's the exact opposite. We should only load the DLL with the exact version of the the Npgsql that's running.

Yes, you're right. I had just enjoyed my coding time. ;) sorry.

I'll prepare fix.

thanks!

@kenjiuno
Copy link
Contributor

kenjiuno commented Dec 5, 2013

@roji

Is it OK for you if we remove the fallback loading

Yes, I don't mind it.

If you request DbProviderServices, try to load tightly coupled Npgsql.EntityFrameworkLegacy first.

And then query NpgsqlServices.TargetProviderServices property.

We can know supported version of DbProviderServices by checking TargetProviderServices.

We provide NpgsqlServices.Instance if we share same version of EntityFramework library.
@kenjiuno
Copy link
Contributor

kenjiuno commented Dec 5, 2013

Hi.

I have changed the approach to Npgsql.EntityFrameworkLegacy.

Premise:

  • Npgsql and Npgsql.EntityFrameworkLegacy is tightly coupled pair connected by their assembly version.

Approach:

  • typeof(DbProviderServices) moved to Npgsql.EntityFrameworkLegacy
  • NpgsqlServices.TargetProviderServices property returns it.
  • At first, load Npgsql.EntityFrameworkLegacy with fully qualified assembly name.
  • And then, query NpgsqlServices.TargetProviderServices
  • At last, Compare Type inside NpgsqlFactory.GetService

kenjiuno/Npgsql@3af882b

I have tested on .NET4.5 (legacyEF & EFv6) and .NET3.5 SP1 legacyEF.

I hope it should work on user's environment as well.

@franciscojunior
Copy link
Member

I also can confirm the error about the System.Data.Entity assembly not found.

I'll also check why it is giving this error.

@franciscojunior
Copy link
Member

After some trial and error this is what I got to make it working:

I changed the initial checking of the GetService() to the following:

if (serviceType.FullName != "System.Data.Common.DbProviderServices")

Would this eliminate the need to load the System.Data.Entity assembly and thus the FileNotFoundException error?

After, that, I started to get errors because he couldn't find the Npgsql.EntityFrameworkLegacy assembly. I just had to add the reference to the project in my solution test.

After that, the test worked like a charm!

Note that I didn't have to add any assembly to the GAC. I tried to get everything using local references.

I also only tried the 4.3.1 EF version using the legacy EF.

I also noticed that the runtime makes a lot of calls to GetService() method. Maybe it should be a good idea to cache the return of npgsqlEntityAssembly.GetType("Npgsql.NpgsqlServices", true);

@roji
Copy link
Member Author

roji commented Dec 5, 2013

I like the approach of looking at the type name rather than loading the assembly, @franciscojunior! It totally circumvents the need to load he entities assembly...

And also the idea to cache the type. I will do both now and add a commit.

I think kenjiuno is using the GAC because he's using an "external" application (EdmGen). Imagine you have some program using entity frameworks. It doesn't know anything about Npgsql but needs to be able to load the Npgsql EF provider (DbProviderServices). So Npgsql (and also Npgsql.EntityFrameworkLegacy) must be in the GAC...

Let me play around and add a commit.

@franciscojunior
Copy link
Member

I like the approach of looking at the type name rather than loading the assembly, @franciscojunior! It totally circumvents the need to load he entities assembly...

And also the idea to cache the type. I will do both now and add a commit.

Great!

I think kenjiuno is using the GAC because he's using an "external" application (EdmGen). Imagine you have some program using entity frameworks. It doesn't know anything about Npgsql but needs to be able to load the Npgsql EF provider (DbProviderServices). So Npgsql (and also Npgsql.EntityFrameworkLegacy) must be in the GAC...

I see.

I'm using a test program which uses EF.

I think he can remove the need to use the GAC if he opens the Npgsql project and adds the edmgen06 as the start program for the project. This way Visual Studio will start edmgen06 using the Npgsql from the project references. @kenjiuno , let me know if you have any problem setting this up.

@roji
Copy link
Member Author

roji commented Dec 5, 2013

I think the point is that a user can't/shouldn't open any projects (neither Npgsql nor edmgen), and doesn't even necessarily have Visual Studio installed to do it...

There's still the important question of how a user is supposed to get the Npgsql.dll and NpgsqlEntityFramework.dll DLLs into the GAC, but let's think about that a bit later...

* Removed #ifdef ENTITIES, which doesn't exist anymore. We have just one Npgsql.dll.
* If the user requests legacy EF but didn't install the EntityFrameworkLegacy package/dll,
  they get an informative exception including the nested exception (is the DLL missing? corrupt?)
* If the required members inside Npgsql.EntityFramework.dll can't be found (e.g. Instance) throw
  an informative exception. This should never happen unless we mess up and release a bad DLL, but still.
* Did not understand what the TargetProviderServices property added, so removed for now
@roji
Copy link
Member Author

roji commented Dec 5, 2013

Oops, I hadn't seen @kenjiuno's work from before :)

OK, I pushed another commit on top of @kenjiuno's work, adding some more informative exceptions and @franciscojunior's proposed caching.

@kenjiuno, look at the commit messages, let me know if I missed something for the TargetProviderServices. As far as I understand, the assembly loading itself ensures that we're always using the correct version of Npgsql.EntityFrameworkLegacy (i.e. the same one as Npgsql), so no need for the additional TargetProviderServices mechanism?

@franciscojunior
Copy link
Member

Em 05/12/2013 14:59, "Shay Rojansky" notifications@github.com escreveu:

I think the point is that a user can't/shouldn't open any projects
(neither Npgsql nor edmgen), and doesn't even necessarily have Visual
Studio installed to do it...

Agreed. I like to use the project reference because I don't need to change
my gac and also because I can debug the calls Npgsql is receiving. Also,
because I'm too lazy and I don't want to gacutil -i every time I create a
new build of Npgsql :-)

There's still the important question of how a user is supposed to get the
Npgsql.dll and NpgsqlEntityFramework.dll DLLs into the GAC, but let's think
about that a bit later...

Yes, I think we should provide some type of installer, or continue to
explain to users that if they need to use Npgsql for many projects and/or
edmgen, they need to install it to gac.

I think the installer would be easier and more practical to the user.


Reply to this email directly or view it on GitHub.

@franciscojunior
Copy link
Member

Em 05/12/2013 15:33, "Shay Rojansky" notifications@github.com escreveu:

Oops, I hadn't seen @kenjiuno's work from before :)

OK, I pushed another commit on top of @kenjiuno's work, adding some more
informative exceptions and @franciscojunior's proposed caching.

Great! I'll test it when I get back home.

@kenjiuno, look at the commit messages, let me know if I missed something
for the TargetProviderServices etc.


Reply to this email directly or view it on GitHub.

@roji
Copy link
Member Author

roji commented Dec 5, 2013

@franciscojunior: great. Let's think of both a DDEX VSI installer and an Npgsaql GAC installed as possible features for 2.2!

We should also move to github issues at some point, this can be documented there with milestones etc...

@kenjiuno
Copy link
Contributor

kenjiuno commented Dec 6, 2013

Hello.

@kenjiuno, look at the commit messages, let me know if I missed something for the TargetProviderServices.

No, no worry. you can remove TargetProviderServices safely, now.

I understood EFv5 is built on top of legacy EF!

I have noticed it today, sorry.

I had a minimal test: we can use current Npgsql+Npgsql.EntityFrameworkLegacy on EFv5 as well as legacy EF.

EF 5.x DbContext Generator also worked for me.

I confirmed it can enumerate entities.

@franciscojunior

This way Visual Studio will start edmgen06 using the Npgsql from the project references. @kenjiuno , let me know if you have any problem setting this up.

No problem. It can be done, even if it is launch on command prompt directly.

Most settings will be done in App.config

  <system.data>
    <DbProviderFactories>
      <remove invariant="Npgsql" />
      <add name="Npgsql Data Provider" 
           invariant="Npgsql" 
           description=".Net Framework Data Provider for PostgreSQL Server" 
           type="Npgsql.NpgsqlFactory, Npgsql" 
           />
    </DbProviderFactories>
  </system.data>
  ...
  <entityFramework>
    <providers>
      <provider invariantName="Npgsql"
                type="Npgsql.NpgsqlServices, Npgsql.EntityFramework, PublicKeyToken=5d8b90d52f46fda7"
                />
    </providers>
  </entityFramework>

Note: I will prepare 3 variants of EdmGen06. [.NET3.5 legacy ef] [.NET4.5 legacy ef] [.NET4.5 EFv6]. Each App.config differs.

If we don't use GAC, partially qualified name is accepted.

If we have already any Npgsql in GAC... It has to be eliminated at first.

This issue will be applied to only our development environment. End users will not concern whether it is installed to GAC or not.

However, in some cases, GAC will be still required:

DDEX support doesn't need GAC at all.

VisualStudio just calls ADO.net (DbConnection and so on) to query database contents.

But there is workaround. Modify DbProviderFactories at runtime. http://stackoverflow.com/questions/1117683/add-a-dbproviderfactory-without-an-app-config

@roji
I will test new commit later. I have not tested it yet.

thank you for your commit!

@kenjiuno
Copy link
Contributor

kenjiuno commented Dec 6, 2013

Hi.

@roji

Let's think of both a DDEX VSI installer and an Npgsaql GAC installed as possible features for 2.2!

It sounds good!
Although I will stick to EdmGen06 due to limitation of VS Express Edition, I'm willing to help it!

And, I have tested the latest commit 086686b.
It will be OK!

I think I have no more problems on new packaging model of Npgsql, for now. thanks!

@roji
Copy link
Member Author

roji commented Dec 6, 2013

Ok @franciscojunior, as far as we know this is now ok. Do your own testing and let me know whether you're ok with it, feel free to merge...

@franciscojunior
Copy link
Member

@franciscojunior: great. Let's think of both a DDEX VSI installer and an Npgsaql GAC installed as possible features for 2.2!

Excellent! I also think so.

We should also move to github issues at some point, this can be documented there with milestones etc...

I agree with you. It would streamline our development process. I'll create a discussion about that in the mailing list.

@roji
Copy link
Member Author

roji commented Dec 6, 2013

So it's OK to merge @franciscojunior? Do you want me to do it?

@franciscojunior
Copy link
Member

Ok @franciscojunior, as far as we know this is now ok. Do your own testing and let me know whether you're ok with it, feel free to merge...

Excellent!

I'll make some tests and will let you know. But from what you and Kenji said, it seems I won't find any problems and we will be ready to go! :)

As soon as I make my tests I'll let you know. And of course I'd like you to make the honor of merging this awesome work :)

@franciscojunior
Copy link
Member

OK. I think it is ready to go.

Shay, please, make the honor and merge this pull request. :-)
Em 06/12/2013 10:17, "Shay Rojansky" notifications@github.com escreveu:

So it's OK to merge @franciscojunior https://github.com/franciscojunior?
Do you want me to do it?


Reply to this email directly or view it on GitHubhttps://github.com//pull/110#issuecomment-29985955
.

@franciscojunior
Copy link
Member

Shay, I don't know if you saw my last message, but I already did some tests here and it worked beautifully!

Ready to merge!

roji added a commit that referenced this pull request Dec 6, 2013
Entity framework work for release 2.1.0
@roji roji merged commit f56c377 into npgsql:master Dec 6, 2013
@roji roji deleted the ef6 branch December 6, 2013 15:43
@roji
Copy link
Member Author

roji commented Dec 6, 2013

OK, merged :)

I also updated the build server config, and it now creates the three nugets along with their symbol packages automatically. Releases should get very easy from now on :)

nuget

@franciscojunior
Copy link
Member

Sweet!

Awesome, Shay! This will help our users get better and faster Npgsql releases!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants