zzzprojects / EntityFramework-Classic

Entity Framework Classic is a supported version of the latest EF6 codebase. It supports .NET Framework and .NET Core and overcomes some EF limitations by adding tons of must-haves built-in features.
https://entityframework-classic.net
Other
103 stars 27 forks source link

HierarchyId support #30

Closed rmaenk closed 5 years ago

rmaenk commented 5 years ago

Hello, We have a license for EF Classic, but cannot migrate our code to it because of absent HierarchyId support. It would be very helpful if HierachyId will be introduced. We used EF beta nightly build and everything is OK. More details here: https://github.com/aspnet/EntityFramework6/commit/f905073aa5a1201a896f57683164e6ea5c4660e2. Thanks, Roman

JonathanMagnan commented 5 years ago

Hello @Roamel ,

Thank you for reporting.

We will look at it and merge this pull as well.

I believe it should be available for next Monday.

Best Regards,

Jonathan

JonathanMagnan commented 5 years ago

Hello @Roamel ,

The v7.0.39 has been released.

Could you try it and let us know if everything is working for HierarchyId?

rmaenk commented 5 years ago

Hello @JonathanMagnan,

I will look into this in few days

Regards, Roman

rmaenk commented 5 years ago

Hello @JonathanMagnan

I have tested the next versions: 7.0.39, 7.0.40 and 7.1.1 For all these versions basic functionality of HierarchyID is working well, like in EF beta version we use.

However, there is an issue with Bulk operations:

Server Error in '/' Application.

Type not supported yet (LazyType): hierarchyid 
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.Exception: Type not supported yet (LazyType): hierarchyid

Source Error: 

Line 169: }
Line 170: if (addEntities.Any()) {
Line 171: _cntx.BulkInsert(addEntities);
Line 172: //using (var bulk = new Z.BulkOperations.BulkOperation<UserDiscipline>(_cntx.Database.Connection)) {
Line 173: // bulk.Connection.Open();

Stack Trace:

[Exception: Type not supported yet (LazyType): hierarchyid]
.(String , PrimitiveType ) +433
<>c.(Property ) +13
System.Collections.Generic.List`1.ForEach(Action`1 action) +85
.(SchemaEntityType ) +680
System.Collections.Generic.List`1.ForEach(Action`1 action) +85
.(Schema , Boolean ) +70
.(Schema , Boolean ) +42
.(XDocument ) +591
.(DbContext ) +151
.(DbContext ) +135
.(DbContext this) +123
.(DbContext this, String ) +36
.(DbContext this, BulkOperation`1 , IEnumerable`1 , List`1 ) +224
.(BulkOperation`1 this, DbContext , IEnumerable`1 , List`1 ) +59
DbContextExtensions.BulkInsert(DbContext this, IEnumerable`1 entities, Action`1 bulkOperationFactory) +889
DbContextExtensions.BulkInsert(DbContext this, IEnumerable`1 entities) +55

If we use Z.BulkOperations.BulkOperation directly - bulk insert works without errors. Like this:

                //_cntx.BulkInsert(addEntities);
                using (var bulk = new Z.BulkOperations.BulkOperation<UserDiscipline>(_cntx.Database.Connection)) {
                    bulk.Connection.Open();
                    bulk.BulkInsert(addEntities);
                    bulk.Connection.Close();
                }

Model is the next (simplified):

    public partial class UserDiscipline {
        public int Id { get; set; }
        public int UserId { get; set; }
        public int DisciplineId { get; set; }
        public virtual Discipline Discipline { get; set; }
        public virtual User User { get; set; }
    }
    [Serializable]
    public partial class Discipline {
        public Discipline() {
            this.Folders = new List<Folder>();
            this.UserDisciplines = new ObservableCollection<UserDiscipline>();
        }

        public int Id { get; set; }
        public virtual ICollection<Folder> Folders { get; set; }
        public virtual ObservableCollection<UserDiscipline> UserDisciplines { get; set; }
    }

    [Serializable]
    public partial class Folder  {
        public Folder() {
            this.Children = new List<Folder>();
        }

        public int Id { get; set; }
        public Nullable<int> ParentFolderId { get; set; }
        public HierarchyId Hid { get; set; }
        public Nullable<int> DisciplineId { get; set; }
        public virtual Discipline Discipline { get; set; }
        public virtual ICollection<Folder> Children { get; set; }
        public virtual Folder Parent { get; set; }
    }

Additionally, not sure is it related to the issue or not, we still use standard EF in parallel, because of Microsoft.AspNet.Identity.EntityFramework package.

Standard EF and Z.Classic both uses the same assembly with models and each load dynamically created assembly with the same full qualified name: EntityFrameworkDynamicProxies-{assembly name here},1.0.0.0.

This may be a cause of the issue, may be not, but 2 assemblies, with the same name, conflict each other during deserialization of proxies. I may suggest to use different assembly name for EntityFrameworkDynamicProxies in Z.Classic, like this: ZEntityFrameworkClassicDynamicProxies-{assembly name here}.(you can look at the code here \src\Shared\EntityFramework\Core\Objects\Internal\EntityProxyFactory.cs)

So, we have some progress with migarting to the library, but it still has some issue that would be good to resolve.

Regards, Roman

JonathanMagnan commented 5 years ago

Hello @Roamel ,

You are right, we forget to add it in our EF Extensions library. I believe this request will be very easy (probably very similar to how we did it with SqlGeometry and SqlGeography).

We also added a task with your suggestion for Dynamic Proxy. We will look at it and should be released this week as well if that's simple to implement.

Best Regards,

Jonathan

JonathanMagnan commented 5 years ago

Hello @Roamel ,

The v7.1.2 has been released.

HierarchyId should now work correctly with Bulk Operations as well.

We will start to check about Dynamic Proxy very soon.

rmaenk commented 5 years ago

Hello @JonathanMagnan Thanks for informing about this. FYI: About Dynamic Proxies: To have both EF and Z.Classic in the same code we use extern aliases: for referencing standard EF: alias in reference props has "EF6" value ("global" is removed) for referencing Z.Classic: alias in reference props has "global" value And in code before usings: extern alias EF6;

static UsersContext() {
            EF6.System.Data.Entity.Database.SetInitializer<UsersContext>(null);
}

Regards, Roman

rmaenk commented 5 years ago

Hello @JonathanMagnan I have tested version 7.1.2 and can confirm that it works with Bulk Operations and HierarchyID without errors with our model. Good work!

FYI: I have found that Update-Database powershel cmdlet does not work if EF context is based on Z.EntityFramework.Classic DBContext and config section name is not default (for instance entityFrameworkClassic instead of entityFramework):

    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
    <section name="entityFrameworkClassic" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, Z.EntityFramework.Classic, Version=7.0.0.0, Culture=neutral, PublicKeyToken=afc61983f100d280" requirePermission="false" />

To fix this static constructor of migration Configuration class can be used :

        static Configuration() {
            Z.EntityFramework.Classic.EntityFrameworkManager.ConfigSectionName = "entityFrameworkClassic";
        }

I know, that initially, Z.EntityFramework.Classic was positioned as replacement for standard EF6 and parallel usage of both libraries was not supported. But now, it looks possible and may help developers to use benefits of this approach. For instance, with packages that cannot be recompiled with Z.EntityFramework.Classic, like Microsoft.AspNet.Identity.EntityFramework. What do you think about adding this to documentation?

Best Regards, Roman

JonathanMagnan commented 5 years ago

Yup it will for sure eventually be added in the doc, thank for sharing ;)

rmaenk commented 5 years ago

Hi @JonathanMagnan

Any news about Dynamic Proxy assembly name change?

Regards, Roman

JonathanMagnan commented 5 years ago

Hello @Roamel ,

I modified the priority on this request.

It seems the priority was very low so was keeping being delayed by other requests.

I will contact you next Monday to give you an update about it. This request should be checked during the weekend and completed if possible.

Best Regards,

Jonathan

JonathanMagnan commented 5 years ago

Hello @Roamel ,

The v7.1.3 has been released.

We renamed the proxy class as you proposed.

Let me know if some request is still remaining or we can close this issue.

Best Regards,

Jonathan

JonathanMagnan commented 5 years ago

Hello @Roamel ,

We will close this issue,

If there is anything else, feel free to comment it here or open a new issue.

Best Regards,

Jonathan

rmaenk commented 5 years ago

Hello @JonathanMagnan Sorry for delay. Everything is working good. Thanks a lot, Roman

mshojaei commented 4 years ago

Hello @JonathanMagnan Sorry I have a provlem when I want to use z.EntityFramework.Classic with Microsoft.AspNet.Identity.EntityFramework

the problem is that both of them used EF, and I cant use DbContext of Microsoft.AspNet.Identity.EntityFramework can you guide me? image

JonathanMagnan commented 4 years ago

Hello @mshojaei ,

Please read the following page, it should help you: https://entityframework-classic.net/using-ef-classic-with-ef-6