1

When you create migration in EF Core you can spice it up with arbitrary SQL query. Yet there is a limit to it -- maybe the migration is too complex in technical sense (i.e the SQL cannot handle it) or in readability sense (expressing the logic in SQL is too muddy). In short when migration logic can be only expressed in regular EF Core C# code with queries, filters, loops, ifs, etc.

Which leads to the question what are the patterns/solutions to handle/organize it?

So far I came up with idea of "freezing" type definitons (by copying them) of context, table models, and call of them let's say "FrozenVersion". Then on migration check if upcoming migration contains the "hot" step -- if yes, migrate it up to this step using FrozenVersion, execute special logic using this version, then disconnect from DB, switch to regular/current version of DB context, and models, connect back to DB, and migrate the rest using this version.

Clarification: this is general question about pattern which starts with "assume SQL is not enough for migration..." in the same sense as patterns for specific algorithms start "assume you have more data than RAM...".

16
  • 7
    I have yet too see an overly complex SQL query which cannot split up into smaller queries or implemented by a stored procedure in a sufficiently clean way.
    – Doc Brown
    Commented Aug 27 at 5:07
  • 3
    @greenoldman No guideline is going to protect you from not leveraging the tools you're working with. The approach you are suggesting (and the limitations you bring up in the comment) are not the idiomatic intended use case for EF. If you struggle leveraging the tool, it would be better to upskill rather than try and come up with a different approach based on not feeling confident enough to write something readable.
    – Flater
    Commented Aug 27 at 8:21
  • 1
    @greenoldman: my personal experience with this community is that responses are much better received here when the overall tone stays polite and constructive. Personal accusations are not welcome here.
    – Doc Brown
    Commented Aug 27 at 11:26
  • 2
    @greenoldman: The secondary issues you bring up (not being able to write readable code, half-understanding your work, completely not understanding your work over time, not wanting to learn a skill on the possibility that you might not need it permanently, ...) are all indicators that you have an ongoing struggle with the skillset for your role. That's not meant to be mean, it's meant to indicate to you that things get way easier when you upskill. A dev who is afraid of the code they write because they fear not understanding it, is holding themselves back and not delivering what they could.
    – Flater
    Commented Aug 27 at 23:04
  • 3
    @greenoldman: well, SQL is probably the most compact solution for most of these problems, and in my eyes often the most readable and maintainable approach, so this is very opinionated and not objectively answerable. But if you stick to the technical question - including LINQ queries instead of SQL in a migration - that would be a good question for Stackoverflow, since it is a coding question about entity framework.
    – Doc Brown
    Commented Aug 28 at 5:44

2 Answers 2

1

The idea behind the MigrationBuilder class is IMHO the other way round:

  1. It contains C# methods for the most common Schema changes as well as the most common data migrations,

  2. and in case the standard methods of a MigrationBuilder cannot handle a migration, there is MigrationBuilder.Sql as the tool for handling any kind of complex migration.

In my experience, the number of cases which cannot be handled by these tools is quite rare. The SQL dialect of any DBMS I know allows to manipulate any kind of internal structure, all kind of things the standard MigrationBuilder methods don't provide.

Now you raised the question what to do when both of the former methods don't seem to be sufficient, and if it is possible to implement, for example, a complex data migration, without SQL, fully in C#, making use of tools like LINQ. Some reasons to justify this step are quite debatable, especially when it comes to "half-knowledge of SQL", because

  • a certain knowledge of SQL is IMHO mandatory for anyone who calls themselves a professsional database programmer

  • when the SQL gets "too muddy", I think chances are high it can be refactored into smaller, cleaner steps

  • when a programmer has trouble to implement a complex migration with SQL in a clean way, they can always ask at a site like Stackoverflow or Codereview.Stackexchange

Still I think your question is certainly justified since I can imagine a few cases where it is indeed easier to implement something in C# than in SQL.

Maybe one needs to include a special library to make some complex technical calculation during a migration, maybe one wants to make use of things provided by the .Net framework or other existing code. For such cases, this Stackoverflow Q&A demonstrates how to get direct access to the database context during a migration, which is all one needs to implement arbitrary C# code which runs as part of migration step.

My priorities for designing a migration would always be (1) MigrationBuilder's standard methods, (2) the Sql method, and (3) custom C#. At least I would not lightheartly choose (3) over (2) just because to avoid SQL programming.

5
  • Thank you, but please keep at heart your own recommendation. It is seriously annoying to be patronized again and again just because I asked shocking/unpopular question. Example -- where did I write "just to avoid writing SQL"? It is your assumption and is plain false. I appreciate your input and help but it would be better without such remarks, let's stick to technical aspects. Option (3) is something I work on to have it in my toolbox but "having" does not mean "using". Yet I want to have it well thought of, and well prepared. And with your help (link to SO) it takes better shapes it had -). Commented Aug 28 at 10:52
  • @greenoldman: "where did I write "just to avoid writing SQL" - in your very first comments below your own question? At least that is how I understood them. And what makes you think your question is unpopular? It got two upvotes (one from me, btw.,), and only one downvote.
    – Doc Brown
    Commented Aug 28 at 11:42
  • Oh, I see :-) Maybe I was not clear enough about it -- I am not for avoiding XYZ per se, but avoiding writing XYZ code at the limits of my knowledge using pieces grabbed all over internet (here XYZ=SQL). As for popularity -- I noticed how fast it got downvote and request for closing it :-). Commented Aug 28 at 15:49
  • @greenoldman: the downvotes and close votes are quite normal here, because there are some hardliners in the community which downvote and close vote everything which contains just a minor sign of being too broad. The wording "what are the patterns/solutions" is often a red flag for them (and others), since it is literally a list of things question, and also a "shopping for patterns" question. ...
    – Doc Brown
    Commented Aug 28 at 16:13
  • ... you will get better reactions when you ask for "an approach (for this specific problem)" instead of "a list of patterns".
    – Doc Brown
    Commented Aug 28 at 16:15
0

I think here you have to go back to the general practice of:

  1. Testing your upgrades/migrations. ie, can v1 migrate to v2,v3,v4 without data loss
  2. Checking the version you are upgrading is on that tested list before upgrading.

If you can't make the jump from v1 to v9, then error out and tell the user to go through whatever intermediate steps are required.

To clarify, if there is some DB transformation that's impossible to do with EF migrations. Don't try and force it into EF migrations with duplicate models and such.

Just do it with sql scripts as a special upgrade, and don't allow migrations that span the problem version (or any other untested upgrade) to run at all.

Second clarification from conversation in comments:

The question asker does not have a deployment or upgrade step, they are just overwriting the exe and running it, so the migrations get triggered, but no extra code.

What I'm suggesting is that you add some sort of deployment or patch process where you can execute arbitrary code when the software is updated.

If you have a CD pipeline to a shared service this is easy, just add more steps there.

If its desktop software, wrap the exe in a launcher which checks for updates and downloads and installs patches.

Once you have that extra step outside of just running the app, you can do all these annoying tasks easy peasy

14
  • Your recommendation is of course true, and I support it, but it is too general to apply. I am asking how to achieve this goal if you have to support migration with actual C# code. The approach I described looks like the best for me, but maybe I am missing something (maybe someone was already in such situation, etc). Commented Aug 27 at 5:33
  • 3
    You don't go into a lot of detail on what you can't achieve with migrations specifically, so I'm answering on the basis that there is some impossible transformation and my answer is to avoid it by using versioning and updates rather than migrations. ie you have some special upgrade v4 -> v5 which you handle outside of migrations and then you make all spanning upgrades other than 4->5, ie 1-> 6 error out instead of trying to cope with the bigger transformation
    – Ewan
    Commented Aug 27 at 8:17
  • I am not sure if this helps, but part of the migration is altering tables (adding new columns, etc) -- this will be covered by SQL of course. The second part is computing the values for those new fields. Writing computation on C# side is trivial, but doing so is somewhat breaking the limits of EF Core migration concepts. On the other hand writing computation on SQL side is convoluted. I am looking (outside this post) how to simplify the second approach (SQL-only), here I am looking how to minimize the impact of the first approach. Later, when I have more information I will decide what to pick. Commented Aug 27 at 10:19
  • hmm yeah that seems like it goes beyond "EF migrations", they are just supposed to be dealing with the database schema. If you have calculated fields, its unclear why you would do those on the DB, you could add them as calculated columns in the DB, or as properties on your objects?
    – Ewan
    Commented Aug 27 at 10:31
  • 2
    OK, so that's the step you are missing. rather than just running the new exe you should have an upgrade process
    – Ewan
    Commented Aug 27 at 13:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.