Skip to content

Unofficial EF Core 6 support #111

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

Closed
bairog opened this issue Dec 13, 2021 · 69 comments
Closed

Unofficial EF Core 6 support #111

bairog opened this issue Dec 13, 2021 · 69 comments

Comments

@bairog
Copy link

bairog commented Dec 13, 2021

Created to continue discussion on EF core 6 support that was started here

@bairog bairog mentioned this issue Dec 13, 2021
@lauxjpn lauxjpn changed the title EF Core 6 support Unofficial EF Core 6 support Dec 13, 2021
@lauxjpn
Copy link
Member

lauxjpn commented Dec 13, 2021

@bairog If you feel like it, give the attached a try. They are currently a work in progress. The EF5/Net5 is at the exact stage the the .Net 5 pull request is at. Compiled from my net5structure branch https://github.com/ChrisJollyAU/EntityFrameworkCore.Jet/tree/net5structure
The .Net 6 (my branch https://github.com/ChrisJollyAU/EntityFrameworkCore.Jet/tree/net6) is copied from the .Net 5 and updated so that it can compile. I've done some basic reading and writing in it but no idea on the more complex stuff
ef6.zip
ef5.zip

Unzip to the project and manually add as reference.

If you prefer a nuget package, you may have to wait for @lauxjpn to finish the tests and merge so that it will show in the nightly builds

Originally posted by @ChrisJollyAU in #98 (comment)

@lauxjpn
Copy link
Member

lauxjpn commented Dec 13, 2021

@ChrisJollyAU Thank you for your work.
I've tried to test your ef6.zip.

Database that I need to query has a lot of specific: table names are Cyrillic, tables has no primary key, colums names are Cyrillic.
So I've created .NET 6.0 class library, added EntityFrameworkCore.Jet.dll, EntityFrameworkCore.Jet.Data.dll and EntityFrameworkCore.Jet.OleDb.dll as a library reference and wrote the following code:

My entites and DbContext in a .NET 6.0 class library
public partial class TechnicalLibraryCatalogItem
    {
        public Int32? OrderNo { get; set; }

        public String? InventoryNo { get; set; }
    }

public partial class TechnicalLibraryContext : DbContext
    {
        public TechnicalLibraryContext()
        {
        }

        public TechnicalLibraryContext(DbContextOptions<TechnicalLibraryContext> options)
            : base(options)
        {
        }

        public virtual DbSet<TechnicalLibraryCatalogItem> TechnicalLibraryCatalogItems { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
                optionsBuilder.UseJet(@"Provider=Microsoft.ACE.OLEDB.12.0;Data Source=EKTB.mdb;");
            }
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<TechnicalLibraryCatalog>().HasNoKey();
            modelBuilder.Entity<TechnicalLibraryCatalog>().ToTable("Каталог ТБ");
            modelBuilder.Entity<TechnicalLibraryCatalog>().Property(tlc => tlc.OrderNo).HasColumnName("№ п/п");
            modelBuilder.Entity<TechnicalLibraryCatalog>().Property(tlc => tlc.InventoryNo).HasColumnName("Инв  №");
        }
    }
My code to read data from ASP .NET Core 6.0 Web App
using (var scope = app.Services.CreateScope())
    {
        var services = scope.ServiceProvider;        

        using (var context = services.GetRequiredService<TechnicalLibraryContext>())
        {
             var lst = context.TechnicalLibraryCatalogItems.ToList();
        }
    }

I've compiled it but get the following error in runtime at .UseJet() line

System.TypeLoadException: 'To use OLE DB in conjunction with Jet, please reference the 'System.Data.OleDb' (version >= 5.0.0) NuGet package.'

I've added a nuget reference for latest System.Data.OleDb 6.0.0 to a class library project and now I have the following error on context.TechnicalLibraryCatalogItems.ToList() line:

System.ArgumentNullException: "Value cannot be null. (Parameter 'provider')"

Stack trace
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel(Boolean designTime)
   at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
   at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__8_4(IServiceProvider p)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass2_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
   at Microsoft.EntityFrameworkCore.DbContext.get_ContextServices()
   at Microsoft.EntityFrameworkCore.DbContext.get_Model()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityType()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.CheckState()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.get_EntityQueryable()
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.System.Collections.Generic.IEnumerable<TEntity>.GetEnumerator()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Program.<<Main>$>g__CreateDatabaseIfNotExists|0_3(WebApplication app) in D:\Tabit.NET_DBPlanov\DBPlanov.Web\Program.cs:line 109

After that I've tried to reverse engineer my existing MS Access database as advised in wiki.
In Package Manager Console (Tools –> NuGet Package Manager –> Package Manager Console) I've wrote
Install-Package Microsoft.EntityFrameworkCore.Tools
and after that:
Scaffold-DbContext -Connection "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=D:\MyDB.mdb;" -Provider EntityFrameworkCore.Jet
But it failed with an error:

System.InvalidOperationException: Unable to resolve service for type 'Microsoft.EntityFrameworkCore.Diagnostics.IDiagnosticsLogger`1[Microsoft.EntityFrameworkCore.DbLoggerCategory+Scaffolding]' while attempting to activate 'EntityFrameworkCore.Jet.Scaffolding.Internal.JetDatabaseModelFactory'.

Stack trace
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.EntityFrameworkCore.Design.Internal.DatabaseOperations.ScaffoldContext(String provider, String connectionString, String outputDir, String outputContextDir, String dbContextClassName, IEnumerable`1 schemas, IEnumerable`1 tables, String modelNamespace, String contextNamespace, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames, Boolean suppressOnConfiguring, Boolean noPluralize)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContextImpl(String provider, String connectionString, String outputDir, String outputDbContextDir, String dbContextClassName, IEnumerable`1 schemaFilters, IEnumerable`1 tableFilters, String modelNamespace, String contextNamespace, Boolean useDataAnnotations, Boolean overwriteFiles, Boolean useDatabaseNames, Boolean suppressOnConfiguring, Boolean noPluarlize)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.ScaffoldContext.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)

In MS docs there is only Microsoft.EntityFrameworkCore.Diagnostics.IDiagnosticsLogger for EF Core 5.0, not for EF Core 6.0.
So I'm in a deadend for now. Any advices are appreciated. Thank you in advance.

Originally posted by @bairog in #98 (comment)

@lauxjpn
Copy link
Member

lauxjpn commented Dec 13, 2021

You might be missing some references
image
Need all 3

Originally posted by @ChrisJollyAU in #98 (comment)

@lauxjpn
Copy link
Member

lauxjpn commented Dec 13, 2021

@ChrisJollyAU
Unfortunatelly I've already tried that with no success (errors are the same). All three libraries (as well as System.Data.OleDb.dll) are present in output directory. I've updated my initial post above.
P. S. I've also tried to call my class library API from a console app instead of ASP .NET Core 6.0 Web App - nothing changes..
Maybe you can share a working example for data reading that you've performed your tests on?

Originally posted by @bairog in #98 (comment)

@lauxjpn
Copy link
Member

lauxjpn commented Dec 13, 2021

I don't see any thing related to Jet in the stack traces. Looks like it's just around in ef core.

Also, not sure what you're trying to do with the scope and serviceProvider.
DbContextOptionsBuilder builder = new DbContextOptionsBuilder<ModelContext>(); builder.UseJet("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\\test\\recent.mdb;").UseLazyLoadingProxies(); context = new ModelContext((DbContextOptions<ModelContext>)builder.Options);

That's how I do it in my console program. Then just use context as normal

Originally posted by @ChrisJollyAU in #98 (comment)

@lauxjpn
Copy link
Member

lauxjpn commented Dec 13, 2021

@ChrisJollyAU
Just changed my code to this - unfortunatelly same error

DbContextOptionsBuilder builder = new DbContextOptionsBuilder<TechnicalLibraryContext>(); 
builder.UseJet("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=D:\\MyDB.mdb;"); 
var context = new TechnicalLibraryContext((DbContextOptions<TechnicalLibraryContext>)builder.Options);
var lst = context.TechnicalLibraryCatalogItems.ToList();

Ok, I will try to perform a test with "traditional" MS database (with English table names and column names) - maybe that is the core of the problem here...

Originally posted by @bairog in #98 (comment)

@lauxjpn
Copy link
Member

lauxjpn commented Dec 13, 2021

@ChrisJollyAU
Same error with "traditional" MS database. Could you please share a full code of your EF6 test console app (including test database) - so I could finally find the real core of my problem? Thank you in advance..

Originally posted by @bairog in #98 (comment)

@lauxjpn
Copy link
Member

lauxjpn commented Dec 13, 2021

Actually, might have the same problem on ef6. It is experimental right now. Also perhaps should have a separate issue for ef6 experimental stuff

Originally posted by @ChrisJollyAU in #98 (comment)

@lauxjpn
Copy link
Member

lauxjpn commented Dec 13, 2021

I changed the title to Unofficial EF Core 6 support, since we will not make any official advances towards EF Core 6 until the EF Core 5 supporting release is out.

@ChrisJollyAU
Copy link
Member

Cool. @lauxjpn Looks like I have the same problem as you had here dotnet/efcore#26260

@lauxjpn
Copy link
Member

lauxjpn commented Dec 13, 2021

Yeah, there are a couple of hiccups when upgrading to 6.0.

@ChrisJollyAU
Copy link
Member

@lauxjpn Think I've got it working now. Some things in the JetQuerySqlGenerator I had to comment out. It just uses the base function for now til I have another look at redoing it for the functionality it had without using the sqlexpressionfactory

@bairog If you feel like it give the attached a try. Looks like it works. Have only done 1 test on it though. Just a basic entity query context.Entity.ToList() . So far it worked and pulled ~40,000 rows without any problems.
ef6.zip

(Standard disclaimer - this is pre-alpha experimental)

@bairog
Copy link
Author

bairog commented Dec 14, 2021

@bairog If you feel like it give the attached a try. Looks like it works. Have only done 1 test on it though. Just a basic entity query context.Entity.ToList() . So far it worked and pulled ~40,000 rows without any problems. ef6.zip

@ChrisJollyAU I've tested the attached libraries in my console application with .net6.0-windows7.0 TFM.
Basic reading with .Where() filtering is working as expected. Many thanks.

@tb-mtg
Copy link

tb-mtg commented May 6, 2022

I have submitted a pull request that compiles and is based on the v5.0.0-alpha.1 tag with dependencies updated to latest versions & targets .net6.

@chrisdreams13
Copy link

chrisdreams13 commented Jul 9, 2022

Any update about the official release for .net6? 5 months ago v5.0.0-alpha.1 is on nuget and it's not compatible with EF 6 (actual 6.0.6).

Version conflict detected for Microsoft.EntityFrameworkCore. Install/reference Microsoft.EntityFrameworkCore 6.0.6 directly to project XXX to resolve this issue.
DBMigrations -> Microsoft.EntityFrameworkCore (>= 6.0.6)
DBMigrations -> EntityFrameworkCore.Jet 5.0.0-alpha.1 -> Microsoft.EntityFrameworkCore (>= 5.0.14 && < 6.0.0)

@ethylon
Copy link

ethylon commented Aug 12, 2022

Any update on this? Or even .net 5?
Microsoft has already ended support for .net 5, maybe you should make LTS versions (.net 6, .net 8) a priority. Wish I could help, but I have no idea how this all works, so I can only count on you guys 😄

@nicovil
Copy link

nicovil commented Sep 8, 2022

I'm trying to make the provider work in .net 6 and there are several changes between frameworks.
One big change was in Migration, I think I'm missing something in IDesignTimeServices.

I changed the ConfigureDesignTimeServices method to make it look similar to the one in SQL Server provider, and introduced JetCSharpRuntimeAnnotationCodeGenerator which implements ICSharpRuntimeAnnotationCodeGenerator.

I'm testing with a simple model creating a couple of tables with a primary key and a foreign key, and for some reason when I do an Add-Migration call, it works but misses 2 things in the generated migration class:

1.- Annotation("Jet:Identity", "1, 1") is not added to the primary key in the "columns" property at CreateTable calls (it was being generated correctly on .net 5 provider)
2.- onDelete entry in table.ForeignKey is not generated at all, which also was working well with the .net 5 provider

I wonder if someone knows what I could be missing to handle those 2 items on new services introduced for .net 6 entity framework.

Maybe some developer could guide me to know which class was the responsible of adding those annotations, I think it may be something related with JetAnnotationCodeGenerator, but cannot figure which method is needed to be overriden to make those 2 properties work.

Another usefull info is that if I run the Migration class generated by .net 5 provider using .net 6 build it creates the tables, primary keys (autoincremental) and foreign keys perfectly, which leads me to think that this is only a problem with the Migration class generation/scaffolding.

Any help will be appreciated!

I know there are no plans for .net 6 support untill .net 5 build is out, however maybe it could help to have a .net 6 branch to work on it, since .net 5 is not supported anymore by Microsoft.

@lauxjpn, if you think my contributions may help, you can create a .net 6 support branch and I can make a pull request on this branch with all my changes that doesn't make a full working build at all (like .net 5, not all unit tests are working because lot of them need a redesign), but I think is a good start because it supports basic functionality, and compiles with .net 6.0.8, and maybe someone from the team could help to improve it.

@ShamilS
Copy link

ShamilS commented Sep 26, 2022

I have got "Disable savepoint API, because it is not supported by Jet" issue while using EFCore.Jet.NET6 codebase.

In general (on first glance, after a few tests with sample Nortwind database) EFCore.Jet.NET6 seems to be working rather well. It would be helpful to have EF Core 5 and EF Core 6 merged with EF Core 6 becoming the main codebase.

@nicovil
Copy link

nicovil commented Sep 26, 2022

I have got "Disable savepoint API, because it is not supported by Jet" issue while using EFCore.Jet.NET6 codebase.

In general (on first glance, after a few tests with sample Nortwind database) EFCore.Jet.NET6 seems to be working rather well. It would be helpful to have EF Core 5 and EF Core 6 merged with EF Core 6 becoming the main codebase.

Which repo are you using? https://github.com/ChrisJollyAU/EntityFrameworkCore.Jet/tree/net6 ?

@ChrisJollyAU
Copy link
Member

@ShamilS @nicovil That issue and fix was after my experimental build. I should probably look at merging all the fixes since then and produce a new build

@nicovil
Copy link

nicovil commented Sep 26, 2022

@ShamilS @nicovil That issue and fix was after my experimental build. I should probably look at merging all the fixes since then and produce a new build

@ChrisJollyAU That would be great!
Also for what I saw in your repo the dependencies (Dependencies.targets) are for .net 6.0.0, and we're now in .net 6.0.9, so maybe this needs an update.

I have y working copy updated to latest packages for 6.0.9

@ShamilS
Copy link

ShamilS commented Sep 26, 2022

I have got "Disable savepoint API, because it is not supported by Jet" issue while using EFCore.Jet.NET6 codebase.
In general (on first glance, after a few tests with sample Nortwind database) EFCore.Jet.NET6 seems to be working rather well. It would be helpful to have EF Core 5 and EF Core 6 merged with EF Core 6 becoming the main codebase.

Which repo are you using? https://github.com/ChrisJollyAU/EntityFrameworkCore.Jet/tree/net6 ?

@nicovil I have just checked - downloaded .zip archive from https://github.com/ChrisJollyAU/EntityFrameworkCore.Jet/tree/net6.
Is it correct? I still have the subject error when using transactions.

@ShamilS
Copy link

ShamilS commented Sep 26, 2022

@ShamilS @nicovil That issue and fix was after my experimental build. I should probably look at merging all the fixes since then and produce a new build

@ ChrisJollyAU It would be great! I'd be waiting for your fixes!

@ShamilS
Copy link

ShamilS commented Sep 26, 2022

@ShamilS @nicovil That issue and fix was after my experimental build. I should probably look at merging all the fixes since then and produce a new build

@ChrisJollyAU That would be great! Also for what I saw in your repo the dependencies (Dependencies.targets) are for .net 6.0.0, and we're now in .net 6.0.9, so maybe this needs an update.

I have y working copy updated to latest packages for 6.0.9

@nicovil @ChrisJollyAU Yes, net 6.0.9 as the target .NET (Core) version would be the best option.

@ShamilS
Copy link

ShamilS commented Sep 26, 2022

Here is a short wish list for EFCore.NET.6.0.9+:

  1. .IsClustered(...) fluent API call is not supported and has to be commented out, e.g.

    entity.HasKey(e => e.Id)
        .HasName("Category_PK")
        ; // .IsClustered(false);
    

It would be useful if .IsClustered(...) fluent API call would be just ignored by EFCore.JET6.

  1. .HasColumnType("image") fluent API is not suported and results in runtime error,

     Data type 'image' for property 'Picture' is not supported 
     in this form. Either specify the length explicitly in the type 
    name, for example as 'image(16)', or remove the data type 
    and use APIs such as HasMaxLength to allow EF choose the data type.
    

so it currently has to be commented out:

For example:

entity.Property(e => e.Picture)
  //.HasColumnType("image")
  .HasComment("A picture representing the food category.");

Images are (usually) stored in MS Access files with 'OLE Object/Long Binary Data' data type.

  1. MS Access Binary data type's data corresponding to byte[] type in C# Entity classes and originated from Timestamp data type in MS SQL database

    public byte[]? RowTimeStamp { get; set; }
    

is not properly loaded when DbContext's OnModelCreating() method used .IsRowVersion() and .IsConcurrencyToken() API calls, e.g:

entity.Property(e => e.RowTimeStamp)
     .IsRowVersion()
     .IsConcurrencyToken();

when .IsRowVersion() and .IsConcurrencyToken() are commented out then data is properly loaded and saved to MS Access database.

    entity.Property(e => e.RowTimeStamp)
       //.IsRowVersion()
       //.IsConcurrencyToken()
       ;
  1. It would be also useful to have SET IDENTITY_INSERT ... raw sql call, e.g.,

      ctx.Database.ExecuteSqlRaw($"SET IDENTITY_INSERT [{entityName}] OFF");
    

to be ignored by EFCore.Jet.6.0.9+ to have the same DbContext code working with MS Access and MS SQL backends without conditional compilation or run-time backend-type checks to bypass code not supported by certain backend types.

@ChrisJollyAU
Copy link
Member

@nicovil @ShamilS I've had a look and have updated to 6.0.9 (although if your project was directly referencing 6.0.9 it would be using that as what it is compiled against is set as the minimum required version). I've also merged the fixes from the master branch into my code.

I will note that I haven't gotten to any tests yet. All I know is that it compiles without errors. Will probably be able to do some stuff tomorrow/this week
EntityFrameworkCore.Jet.zip

Also, @ShamilS I will see if there is anything I can do about your points. Some will be easier than others

@ShamilS
Copy link

ShamilS commented Sep 27, 2022

@nicovil @ShamilS I've had a look and have updated to 6.0.9 (although if your project was directly referencing 6.0.9 it would be using that as what it is compiled against is set as the minimum required version). I've also merged the fixes from the master branch into my code.

I will note that I haven't gotten to any tests yet. All I know is that it compiles without errors. Will probably be able to do some stuff tomorrow/this week EntityFrameworkCore.Jet.zip

Also, @ShamilS I will see if there is anything I can do about your points. Some will be easier than others

@ChrisJollyAU Transactions work now. Thanks!

@ShamilS
Copy link

ShamilS commented Sep 29, 2022

@ChrisJollyAU

And that works now.

Yes, I have checked it works, generates expressions for DateTime field type with milliseconds as, e.g

         IIF(`c`.`BestServedAfterDateTime` IS NULL, NULL, CDBL(`c`.`BestServedAfterDateTime`))

It's OdbcException as that is where the error has occurred. EFCore.Jet connects to the access database through either the OleDb or Odbc drivers and sends the SQL through that.

Thank you for clarification.

@ChrisJollyAU
Copy link
Member

ChrisJollyAU commented Oct 3, 2022

@nicovil Are you sure it was working in the 5.0 series?

It's just that I found a test that looked like it has the same problem (the DefaultValuesTest). It has a simple table with the Id declared as
public int Id { get; set; }

And nothing further in the fluent API section. In both the 5.x and 6.x code the CREATE TABLE sql for that field was created as
int NOT NULL

Even using the .ValueGenereatedOnAdd() did not change anything.

Obviously the test was failing as it expected the Id to be an Identity and not needed to be included in the INSERT statement.

The only place where the Jet:Identity annotation is being set is via the .UseIdentityColumn() call

From https://learn.microsoft.com/en-us/ef/core/modeling/keys?tabs=data-annotations#value-generation

For non-composite numeric and GUID primary keys, EF Core sets up value generation for you by convention. For example, a numeric primary key in SQL Server is automatically set up to be an IDENTITY column.

can see that setting a numeric primary key to the identity is the expected situation.

Looking at how Sqlite does it I have updated JetAnnotationProvider.cs to behave the same way

Those tests now work so hopefully your problem should be fixed


A couple more tests were also fixed

  • Coalesce: The function COALESCE isnt supported in Jet. Rewrote to a form Jet can understand. Allows _.Integer ?? 5 in a statement
  • Convert functions should now be working
  • Handle double.Parse and basic entities with the .Parse function, when used in a Where clause
  • The JetDateTimeMemberTranslator was overriding the built-in NullableMemberTranslator for a DateTime?
  • When using a DateTime.Contains function the resulting IN expression did not properly format the DateTime in the list

@nicovil
Copy link

nicovil commented Oct 3, 2022

@nicovil Are you sure it was working in the 5.0 series?

It's just that I found a test that looked like it has the same problem (the DefaultValuesTest). It has a simple table with the Id declared as public int Id { get; set; }

And nothing further in the fluent API section. In both the 5.x and 6.x code the CREATE TABLE sql for that field was created as int NOT NULL

Even using the .ValueGenereatedOnAdd() did not change anything.

Obviously the test was failing as it expected the Id to be an Identity and not needed to be included in the INSERT statement.

The only place where the Jet:Identity annotation is being set is via the .UseIdentityColumn() call

From https://learn.microsoft.com/en-us/ef/core/modeling/keys?tabs=data-annotations#value-generation

For non-composite numeric and GUID primary keys, EF Core sets up value generation for you by convention. For example, a numeric primary key in SQL Server is automatically set up to be an IDENTITY column.

can see that setting a numeric primary key to the identity is the expected situation.

Looking at how Sqlite does it I have updated JetAnnotationProvider.cs to behave the same way

Those tests now work so hopefully your problem should be fixed

Hi @ChrisJollyAU ,

I'm pretty sure it works because I'm using the migration generated class from 5.0 build with my 6.0 working copy.

Are you adding the "HasKey" fluent definition too?

This is the code that I'm using, and 5.0 generated the migration correctly.

builder.HasKey(e => e.WorkElementId)
					.IsClustered(false);

			builder.ToTable("work_element");

			builder.Property(e => e.WorkElementId)
				.HasColumnName("work_element_id")
				.ValueGeneratedOnAdd();

Did you pushed the changes to your repo? I'm going to test your last changes to confirm they work.
Thanks!

@ChrisJollyAU
Copy link
Member

@nicovil Any chance for the full class for the table and the OnConfiguring section for that table for the Fluent API part. So that I can try a test on my side as well
And yes, all changes are pushed to the branch in my repo

@ChrisJollyAU
Copy link
Member

@nicovil Any update? Is it working now? Also are you still having the problem with the foreign keys or is that fixed as well?

@nicovil
Copy link

nicovil commented Oct 10, 2022

@nicovil Any update? Is it working now? Also are you still having the problem with the foreign keys or is that fixed as well?

@ChrisJollyAU Hi Chris, sorry for the delay.
I were not able to test it yet, sorry. I will try to do it today and back to you with feedback.

Thanks!

@nicovil
Copy link

nicovil commented Oct 10, 2022

@nicovil Any chance for the full class for the table and the OnConfiguring section for that table for the Fluent API part. So that I can try a test on my side as well And yes, all changes are pushed to the branch in my repo

Is there some way to send the Fluent configuration file to you?

@nicovil
Copy link

nicovil commented Oct 10, 2022

Hi again @ChrisJollyAU.

I did a full build from your net6 repo, and tried the Add-Migration command, but sadly I'm getting the same error:

Here is the output from Package Manager Console.

PM> Add-Migration Initial-Version -OutputDir "Migrations"
Build started...
Build succeeded.
System.InvalidOperationException: Unable to resolve service for type 'Microsoft.EntityFrameworkCore.Storage.TypeMappingSourceDependencies' while attempting to activate 'EntityFrameworkCore.Jet.Storage.Internal.JetTypeMappingSource'.
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateEnumerable(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, Boolean throwIfCallSiteNotFound)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateConstructorCallSite(ResultCache lifetime, Type serviceType, Type implementationType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(ServiceDescriptor descriptor, Type serviceType, CallSiteChain callSiteChain, Int32 slot)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.TryCreateExact(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateCallSite(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.GetCallSite(Type serviceType, CallSiteChain callSiteChain)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType, String namespace)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
Unable to resolve service for type 'Microsoft.EntityFrameworkCore.Storage.TypeMappingSourceDependencies' while attempting to activate 'EntityFrameworkCore.Jet.Storage.Internal.JetTypeMappingSource'.
PM> 

@ChrisJollyAU
Copy link
Member

@nicovil Thanks. It's an interesting problem as I have often had to debug and step through JetTypeMappingSource when fixing tests.

A couple of questions:

  1. Output of dotnet --info
  2. Which version of Visual Studio
  3. The application you are using, is it targeting Any CPU,x86 or x64?
  4. What happens if you go to the command line and use dotnet ef migrations add Initial-Version

@nicovil
Copy link

nicovil commented Oct 10, 2022

@ChrisJollyAU , here is more info.

If I modify the JetDesignTimeServices class (like I did in my working copy) to this:

public virtual void ConfigureDesignTimeServices(IServiceCollection serviceCollection)
{
			serviceCollection.AddEntityFrameworkJet();

			new EntityFrameworkRelationalDesignServicesBuilder(serviceCollection)
				.TryAdd<IAnnotationCodeGenerator, JetAnnotationCodeGenerator>()
				.TryAdd<IDatabaseModelFactory, JetDatabaseModelFactory>()
				.TryAdd<IProviderConfigurationCodeGenerator, JetCodeGenerator>()
				.TryAddCoreServices();
}

Things are working now, and the generated migration code auto incremental (counter) keys has the Annotation("Jet:Identity", "1, 1") calls.

The generated empty Access database has the counter data type created correctly.

HOWEVER

There is an issue that has not been resolved, the "onDelete" configuration.

In this snapshot you can see the difference between net 5.0 migration code (LEFT) and 6.0 migration code (RIGHT).

imagen

I'm not sure, maybe ReferentialAction.Restrict is the default value for onDelete property, and that's why it's not being generated in 6.0 version?

@nicovil
Copy link

nicovil commented Oct 10, 2022

@nicovil Thanks. It's an interesting problem as I have often had to debug and step through JetTypeMappingSource when fixing tests.

A couple of questions:

1. Output of `dotnet --info`

2. Which version of Visual Studio

3. The application you are using, is it targeting Any CPU,x86 or x64?

4. What happens if you go to the command line and use `dotnet ef migrations add Initial-Version`

Here we go:

(1) my base system is in Spanish, but it's almost the same output.

SDK DE .NET:
 Version:   6.0.401
 Commit:    0906eae6f8

Entorno de tiempo de ejecución:
 OS Name:     Windows
 OS Version:  10.0.19044
 OS Platform: Windows
 RID:         win10-x64
 Base Path:   C:\Program Files\dotnet\sdk\6.0.401\

global.json file:
  Not found

Host:
  Version:      6.0.9
  Architecture: x64
  Commit:       163a63591c

.NET SDKs installed:
  1.0.0 [C:\Program Files\dotnet\sdk]
  1.0.4 [C:\Program Files\dotnet\sdk]
  2.1.4 [C:\Program Files\dotnet\sdk]
  2.1.200 [C:\Program Files\dotnet\sdk]
  2.2.107 [C:\Program Files\dotnet\sdk]
  3.0.100 [C:\Program Files\dotnet\sdk]
  3.1.100 [C:\Program Files\dotnet\sdk]
  3.1.423 [C:\Program Files\dotnet\sdk]
  5.0.201 [C:\Program Files\dotnet\sdk]
  5.0.303 [C:\Program Files\dotnet\sdk]
  5.0.408 [C:\Program Files\dotnet\sdk]
  5.0.412 [C:\Program Files\dotnet\sdk]
  6.0.401 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.All 2.1.30 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.All 2.2.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.All]
  Microsoft.AspNetCore.App 2.1.30 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 2.2.5 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.18 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.19 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.20 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.21 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.22 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.23 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.24 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.26 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.27 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 3.1.29 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.12 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.AspNetCore.App 6.0.9 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 1.0.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 1.0.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 1.1.1 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 1.1.2 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.0.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.0.7 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.1.30 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 2.2.5 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.0.0 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.18 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.19 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.20 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.21 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.22 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.23 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.24 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.26 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.27 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 3.1.29 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.12 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.NETCore.App 6.0.9 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 3.1.18 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.19 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.20 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.21 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.22 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.23 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.24 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.26 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.27 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 3.1.29 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.9 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.12 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 5.0.17 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]
  Microsoft.WindowsDesktop.App 6.0.9 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

Download .NET:
  https://aka.ms/dotnet-download

Learn about .NET Runtimes and SDKs:
  https://aka.ms/dotnet/runtimes-sdk-info

(2)

Visual Studio 2022 Professional, v17.3.5

(3)

Target: AnyCPU, Windows10

(4)

Exactly the same behavior than from package management console.

@nicovil
Copy link

nicovil commented Oct 10, 2022

@nicovil Thanks. It's an interesting problem as I have often had to debug and step through JetTypeMappingSource when fixing tests.

A couple of questions:

1. Output of `dotnet --info`

2. Which version of Visual Studio

3. The application you are using, is it targeting Any CPU,x86 or x64?

4. What happens if you go to the command line and use `dotnet ef migrations add Initial-Version`

I really think the issue is in ConfigureDesignTimeServices.

If you check the SQL Server provider code, you will notice it changed from EF 5.0 to EF 6.0 and that it's now calling the EntityFrameworkRelationalDesignServicesBuilder helper class, plus also calling the AddXXXXX method to register all services for dependency injection.

@ChrisJollyAU
Copy link
Member

@nicovil Yeah. Was just looking to see if it had anything to do with one part being a different bitness to the other. But it seems fine

I've looked at one table that I set the Restrict behaviour to and followed it through its sql generation.
Couple of notes as follows

  • It actually ignores the Restrict when generating the foreign key
  • If I force it to use RESTRICT such as

CREATE TABLE Persons (
Id counter NOT NULL,
Name longchar NOT NULL,
AddressOneId integer NULL,
AddressTwoId integer NULL,
CONSTRAINT PK_Persons PRIMARY KEY (Id),
CONSTRAINT FK_Persons_Addresses_AddressOneId FOREIGN KEY (AddressOneId) REFERENCES Addresses (Id) ON DELETE RESTRICT,
CONSTRAINT FK_Persons_Addresses_AddressTwoId FOREIGN KEY (AddressTwoId) REFERENCES Addresses (Id) ON DELETE RESTRICT
)

I will get a Syntax error in constraint clause error

  • Looking further in the Adox and DAO schema, neither of them support Restrict.

As to what is happening in your migrations, best guess for now is the .Net 5 is including the detail but when generating the SQL it is not doing anything
If you still have the .Net 5 version around you can try see the SQL if you do Script-Migration. Then compare to .Net 6

@ChrisJollyAU
Copy link
Member

@nicovil Think I have it fixed now.
Created a test project and configured the entity as

modelBuilder.Entity<Post>()
.HasOne(p => p.Blog)
.WithMany(b => b.Posts)
.HasForeignKey(e => e.BlogId).OnDelete(DeleteBehavior.Restrict);

Running Add-Migration creates the following

migrationBuilder.CreateTable(
                name: "Posts",
                columns: table => new
                {
                    PostId = table.Column<int>(type: "integer", nullable: false)
                        .Annotation("Jet:Identity", "1, 1"),
                    Title = table.Column<string>(type: "longchar", nullable: false),
                    Content = table.Column<string>(type: "longchar", nullable: false),
                    BlogId = table.Column<int>(type: "integer", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Posts", x => x.PostId);
                    table.ForeignKey(
                        name: "FK_Posts_Blogs_BlogId",
                        column: x => x.BlogId,
                        principalTable: "Blogs",
                        principalColumn: "BlogId",
                        onDelete: ReferentialAction.Restrict);
                });

This is as expected.
Doing the script-migration produces

CREATE TABLE `Posts` (
    `PostId` counter NOT NULL,
    `Title` longchar NOT NULL,
    `Content` longchar NOT NULL,
    `BlogId` integer NOT NULL,
    CONSTRAINT `PK_Posts` PRIMARY KEY (`PostId`),
    CONSTRAINT `FK_Posts_Blogs_BlogId` FOREIGN KEY (`BlogId`) REFERENCES `Blogs` (`BlogId`) ON DELETE NO ACTION
);

Also, as I expected given that there is no Restrict in Jet

@nicovil
Copy link

nicovil commented Oct 12, 2022

@nicovil Think I have it fixed now. Created a test project and configured the entity as

modelBuilder.Entity<Post>()
.HasOne(p => p.Blog)
.WithMany(b => b.Posts)
.HasForeignKey(e => e.BlogId).OnDelete(DeleteBehavior.Restrict);

Running Add-Migration creates the following

migrationBuilder.CreateTable(
                name: "Posts",
                columns: table => new
                {
                    PostId = table.Column<int>(type: "integer", nullable: false)
                        .Annotation("Jet:Identity", "1, 1"),
                    Title = table.Column<string>(type: "longchar", nullable: false),
                    Content = table.Column<string>(type: "longchar", nullable: false),
                    BlogId = table.Column<int>(type: "integer", nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Posts", x => x.PostId);
                    table.ForeignKey(
                        name: "FK_Posts_Blogs_BlogId",
                        column: x => x.BlogId,
                        principalTable: "Blogs",
                        principalColumn: "BlogId",
                        onDelete: ReferentialAction.Restrict);
                });

This is as expected. Doing the script-migration produces

CREATE TABLE `Posts` (
    `PostId` counter NOT NULL,
    `Title` longchar NOT NULL,
    `Content` longchar NOT NULL,
    `BlogId` integer NOT NULL,
    CONSTRAINT `PK_Posts` PRIMARY KEY (`PostId`),
    CONSTRAINT `FK_Posts_Blogs_BlogId` FOREIGN KEY (`BlogId`) REFERENCES `Blogs` (`BlogId`) ON DELETE NO ACTION
);

Also, as I expected given that there is no Restrict in Jet

Hi @ChrisJollyAU .

I updated the code from the repo and made a rebuild, everything seems to be working now.

The only detail, which I don't think is important, is that I was not explicitly setting up restrict mode for the foreign key.

That is, I was not adding the "OnDelete" call in the fluent confuration:

.OnDelete(DeleteBehavior.Restrict);

So, in 5.0 it seems that the migration framework was adding this by default.

Again, I don't think this is important and having the behavior for explicit fluent configuration that you added is a good thing to have.

@ChrisJollyAU
Copy link
Member

The only detail, which I don't think is important, is that I was not explicitly setting up restrict mode for the foreign key.
That is, I was not adding the "OnDelete" call in the fluent confuration:

That's a bit odd. Without knowing the full definition it's a bit hard to say though. Normally EF Core will set it up as on delete cascade if nothing else specified

@nicovil
Copy link

nicovil commented Oct 12, 2022

That's a bit odd. Without knowing the full definition it's a bit hard to say though. Normally EF Core will set it up as on delete cascade if nothing else specified

Here is an example in .net 5.0 to show my point:

This fluent code:


Entity 1: Language

                        builder.HasKey(e => e.DisplayName).IsClustered(false);

			builder.ToTable("languages");

			builder.Property(e => e.DisplayName)
				.HasMaxLength(64)
				.HasColumnName("display_name");

			builder.Property(e => e.Complexity).HasColumnName("complexity");

			builder.Property(e => e.Description)
				.HasMaxLength(255)
				.HasColumnName("description");

			builder.Property(e => e.Factor).HasColumnName("factor");

			builder.Property(e => e.LanguageTypeCode)
				.HasMaxLength(8)
				.HasColumnName("language_type_code");

			builder.HasOne(d => d.LanguageTypeCodeNavigation)
				.WithMany(p => p.Languages)
				.HasForeignKey(d => d.LanguageTypeCode)
				.HasConstraintName("FK_languages_language_types");

Entity 2: LanguageType

                        builder.HasKey(e => e.LanguageTypeCode);

			builder.ToTable("language_types");

			builder.Property(e => e.LanguageTypeCode)
				.HasMaxLength(8)
				.HasColumnName("language_type_code");

			builder.Property(e => e.LanguageTypeDescription)
				.HasMaxLength(2000)
				.IsUnicode(false)
				.HasColumnName("language_type_description");

			builder.Property(e => e.LanguageTypeName)
				.HasMaxLength(64)
				.HasColumnName("language_type_name");

is generating this migration code:

migrationBuilder.CreateTable(
                name: "language_types",
                columns: table => new
                {
                    language_type_code = table.Column<string>(type: "varchar(8)", maxLength: 8, nullable: false),
                    language_type_name = table.Column<string>(type: "varchar(64)", maxLength: 64, nullable: true),
                    language_type_description = table.Column<string>(type: "longchar", unicode: false, maxLength: 2000, nullable: true)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_language_types", x => x.language_type_code);
                });

migrationBuilder.CreateTable(
                name: "languages",
                columns: table => new
                {
                    display_name = table.Column<string>(type: "varchar(64)", maxLength: 64, nullable: false),
                    language_type_code = table.Column<string>(type: "varchar(8)", maxLength: 8, nullable: true),
                    factor = table.Column<double>(type: "double", nullable: true),
                    complexity = table.Column<int>(type: "integer", nullable: true),
                    description = table.Column<string>(type: "varchar(255)", maxLength: 255, nullable: true)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_languages", x => x.display_name);
                    table.ForeignKey(
                        name: "FK_languages_language_types",
                        column: x => x.language_type_code,
                        principalTable: "language_types",
                        principalColumn: "language_type_code",
                        onDelete: ReferentialAction.Restrict);
                });

@nicovil
Copy link

nicovil commented Oct 13, 2022

@ChrisJollyAU ,

My tests with your actual version of the code are going very well, and I'm almost sure I'm having the same behavior than with .net 5 build.
The project I'm working on has a lot of complex stuff, like custom migration operations, multi-dbms support, custom overriden framework services (like CacheKey, etc), custom runtime defined entities, etc, etc... so it's stressing a lot of components.

So, since the actual version seems very stable (equal or even more than net 5.0 version), do you think it's a good time to create a Nuget package (at least an ALPHA release) for .net 6 version? It would be good because lot of people will be testing it there.

Maybe it's time to create a .net5 branch (or tag) in official repo and merge your changes into this main repo's trunk to have it as baseline? (just giving my opinion, of course it's your decision since you're part of the official team)

@ChrisJollyAU
Copy link
Member

@nicovil Thanks for the feedback. Good to know that it seems to be working nicely.

I'd love to get an alpha .Net 6 release out sometime. Best I can do is create a pull request (probably sometime this week) and get the maintainers that do have access to merge it

@nicovil
Copy link

nicovil commented Oct 18, 2022

@nicovil Thanks for the feedback. Good to know that it seems to be working nicely.

I'd love to get an alpha .Net 6 release out sometime. Best I can do is create a pull request (probably sometime this week) and get the maintainers that do have access to merge it

That sounds very good. I guess since you're a contributor they will hear you!

@ChrisJollyAU
Copy link
Member

For those following this thread PR #131 is created

@nicovil
Copy link

nicovil commented Oct 23, 2022

For those following this thread PR #131 is created

Awesome work @ChrisJollyAU.
Thanks you very much for your support!

@ChrisJollyAU
Copy link
Member

Similar to the Ef Core 7, I have updated a number of things

  1. Fixed the Math and String translators. Updated to how current Sql Server generates things. This fixes some tests (both by generating a sql server style code that works as well as handling scenarios not previously handled)
  2. Fixed a number of NorthWind* tests (Mostly in NorthwindFunctions, NorthwindGroupBy, NorthwindAggregate and some others)

At this point in time unlikely to turn on nullable for .Net 6 but maybe in the future

@ChrisJollyAU
Copy link
Member

For all those following, this is now in the master branch

@bairog
Copy link
Author

bairog commented Dec 8, 2022

@ChrisJollyAU Thank you. When approximately we may expect it to be released?

@ChrisJollyAU
Copy link
Member

ChrisJollyAU commented Dec 8, 2022

@bairog Should be on the daily build feed and the nuget feed now. It's still marked as an alpha prerelease.

Standard Jet limitations apply

@ChrisJollyAU ChrisJollyAU pinned this issue Dec 8, 2022
@ChrisJollyAU
Copy link
Member

For those following Beta 1 is now available

Notable improvements are:

  • Fixed replacing global variable placeholders
  • Added JetParameterBaseSqlProcessor and JetSqlNullabilityProcessor. Fixesthe order of how it optimizes nullable values
  • CreateDatabase now tries to use the current provider type instead of defaulting to Odbc
  • Add Floor and Ceiling to Math translations
  • A huge amount of tests were fixed
  • Unrolled COALESCE with 3 or more arguments
  • Finally got the Gears of War tests working (needed a data change to get passed a rather strict foreign key set up)
  • Fixed the Object ToString translator to not handle some things on the server (like enums)
  • Fixed the Convert translator - was picking up a tostring method that required parameters whereas the server was only meant to handle the ones without parameters (often the parameters were a format string or format provider)
  • Fixed some null propagatability in LEN and MID functions (specially MID does not accept NULL for length parameter whereas SQL Server does)

With the 6.0 series I am just trying to fix the bugs. The 7.0 series is where anything big/new will most likely appear

@ChrisJollyAU ChrisJollyAU unpinned this issue Sep 25, 2023
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

No branches or pull requests

8 participants