Search code examples
entity-frameworkentity-framework-corerefactoring

How to plan migration from EF 6 with EDMX to EF Core


We have a pretty complex .EDMX in EF 6.0 which was designed using database-first approach (against SQL Server) back in 2014.

It uses lot of features of EF like TPT, TPC, TPH, entity splitting, custom T4 templates as well along with inheritance, abstraction etc. We have stored procedures, views, even CLR functions (for regex) at some places.

Schema do have 1-1 relationships, 1-N, N-N etc with OOP concepts down at database level even.

This eventually gets used into ASP.NET Web API (not .NET Core) and API gets consumed in WPF, Winforms, Windows services etc.

When I tried porting the API to .NET Core, it was simple. However it did fail when connecting to database with a SqlClient error which is forcing me to upgrade to EF Core.

Scaffolding looks quite messed up with so many entities being generated without any relationships properly defined. Is there a tool or something that can read my existing .edmx file and generate fluent version for the same?

I have already tried EF Core Power Tools. It doesn't seems to be a job of a day or 2 and it looks like a month long job.

Any shortcuts?


Solution

  • (Preamble: my first thought was that this question is too broad for Stack Overflow, but on second thoughts there seems to be a good answer that is not entirely opinion-based, at least good enough for an acceptable SO answer.)

    TL;DR: First convert EDMX code to EF6 code-first. Then port all code to EF-core.

    Unfortunately, there's no readily available tool that does this for you. The process is too complex for that. Maybe AI-based code generation tools come a long way, I never tried.

    The article Port from EF6 to EF Core actually does a pretty good job describing most of the hurdles to take, but for those coming from EDMX, it's pretty scanty. Porting EDMX-based code to EF-core (EFC) is a big, big step.

    Based on my own experience, the greatest challenge is controlling regression. That's much easier when following a couple of steps that do introduce redundancy, but for a good reason:

    • If not yet abundantly present: create integrations test, lots of them. If already present: create just a couple more of them. You will (obviously) run these tests after each of the following steps.

    • Then the process begins. First port the EDMX-based code to "code-first from database", still EF6. The starting point may be reverse-engineering the model from database, either using EF tooling in Visual Studio or third-party tools like Entity Framework 6 Power Tools (I believe that requires VS 2019 though). In my experience, the biggest step in the entire conversion was to get all idiosyncrasies and customizations in EDMX mappings right when converting them to code-based mappings. Although this step seems redundant, it's far easier to control regression: you still have the same application code, so you can focus on making all tests run as-is. Converting this code-based configuration to EFC (later step) is a relatively easy one that will cause less regression.

    • (If applicable) Still in EF6, implement a .Net-core-ready alternative for validation by IValidatableObject, because EF-core doesn't integrate it out-of-the-box anymore. Again, this offers you a regression step without changing application code.

    • Now the "big bang" (but much smaller than it was):

      • Change the NuGet package.
      • Convert the fluent mappings to the EFC methods.
      • Make the rest of the code compile again (namespaces, class names, etc.)
      • Apply .Net-core application startup and configuration, also in the regression test project.
    • Now regression tests will run, but unless you're extremely lucky, many of them will fail, because:

      • EF6 supported a couple of complex, but still pretty common, query shapes that EFC (still) doesn't.
      • Some of the mapping code may need correction.
      • Applying entity state changes has changed in EFC. This is a tough area that's hard to debug. Make sure to scrutinize Behavior Changes between EF6 and EF Core.

      So now for the final step:

    • Make all tests succeed again. In the worst case, this may require thorough changes in application code, but now you have already covered a lot of ground and greatly reduced the number of reasons why tests fail.

    All of this is easier if it can be done in parts. It depends on the application structure (specifically the existence of aggregates) if this is possible. We started with smaller parts to get the hang of it and then proceeded to the big chunks.

    As for migrations: make a new start in EFC. Note that Data Seeding was changed thoroughly.


    To others: please feel free to comment on this and/or make amendments. This is based one personal experience. Although I'm sure these steps are generally applicable, the picture can be broadened and steps be fleshed out by other experiences.