How do I remove a type by migrating fields to parent class? Example: Version 1.0
Version 2.0
I want my instances of B to become instances of A, and Text field to be filled with information defined in B class. Is this possible? How do I do this? I tried with CopyFieldHint, but if I remove B type all my instances are removed. |
Sorry, I discovered that initially we wrote a test for different case (propagation to derived type), so it took some time to test and described this. First of all, there is no easy way to do this now - mainly, because there is no hint allowing to merge two types into one. So if you need to merge Upgrade way 1: RDBMS-indepenent, based on schema hintsOld model:
New model:
Overriding
The description:
The following SQL is executed in this case:
So it's nearly the fastest way to perform such upgrade. Upgrade way 2: RDBMS-dependent, based on direct SQL executionModels are the same. Overriding
As you see, we do nearly the same, but using direct SQL commands. You might notice we use different upgrade stages here - that's because schema hints must be generated in the same stage when schema changes, but Upgrade way 3: RDBMS-independent, based on custom upgrade codeYou may find that usage of direct SQL commands is actually an optimization in previous case. You can achieve the same with this
And actually, I'd advise you to use such code. It's slower than a single update, but must be pretty good as well (DO batches everything batching). But it's easier to understand and refactor. So use this approach, if upgrade performance isn't essential. ConclusionAs you see, the process is a bit tricky first two cases, but such upgrades are possible. The third option is pretty simple, so likely, it will be the best choice in majority of cases. Sadly, I have 1 367 109 instances of this particular class so method 3 is not possible ;) Method 3 will work only if you have few instances : else we risk the timeout and rollback of update. However I did move the fields to 'Base' class without any problem using hints : I just didn't remove the 'Derived' class. So I must use method 1 or 2, but I'd rather wait the development of an "TypeMerge" hint to do this : is it possible that you develop such an hint for next release? I've the feeling we'll get this migration case from time to time, and this UpgradeHint would very helpful.
ASP.NET MVC Sample creates ~ 100K instances on startup. It takes ~ 10 seconds on good PC, entity has several fields. I.e. entity creation performance is about 10K entities per second in case this is a hierarchy root. So in this case it should take about 2.5-3 minutes to handle the migration using this method (it's better to do this in transactions processing ~ 10K entities at once). If you need a single transaction, timeouts can be adjusted to ensure it will be finished, but this will take more time in this case. I think even 1 hour is acceptable time for migrations in most of cases. At least, many Google services (e.g. Google Code) frequently use ~ such time periods for updates.
For now this isn't planned - frankly speaking, I'd prefer to postpone this until release of v4.5 beta (caching + likely, security). We're targeting to release it closer to new year. That's a feature that really simplifies handling such cases, but since typical development pattern with DO is "develop, develop, develop, write a migration code, release", this is isn't what people strongly need in development, + there are workarounds like listed ones. I think it's better to bring few more features first... I'll test method 3 that when I have the time. But how I can split the update in several transaction? In UpgradeHandler there is already an opened transaction for update, so should I do it outside UpgradeHandler? By the way, the duration is not the only problem : if I create 1 million objects in one transaction wouldn't the transaction log grow to an huge size? Another question: with method 3, how do you remove the instances of 'Derived' class? The timing for the new hint is yours : while it's not that important, I think it would be useful.
No, you shouldn't, but you can control it:
Yes, it will. So a solution with intermediate commits might be helpful in such cases.
They'll be automatically removed on 1
Most likely type merge will be done with issue 857 (i.e. as part of v4.4.X). |
Custom upgrade handler must help here:
Upgrade handler code, option 1 (custom upgrade code):
Upgrade handler code, option 2 (with upgrade hints):
Difference between these two versions:
Upgrade handler is a regular class inherited from Xtensive.Storage.Upgrade.UpgradeHandler, that must be registered in Just edited my answer. Very interesting! I missed the RenameTypeHint. I will test this right away. I will add that option 2 is better for performance. I have ~500 000 entities to migrate and that will take forever with option 1. I tried option 2 but I get an exception on Build: "Sequence contains no matching element" Stack: System.Linq.Enumerable.Single[TSource] Xtensive.Storage.Upgrade.HintGenerator.GenerateTypeIdFieldRemoveHintsForConcreteTable() Xtensive.Storage.Upgrade.HintGenerator.GenerateHintsXtensive.Storage.Upgrade.UpgradingDomainBuilder.BuildSchemaHints ... Do you need more information or a sample? Did you apply In worst case, sample is preferable. This definitely should work. I removed the type. If I keep the type (without fields) and add [Recycled], I get an ArgumentException ("An item with the same key has already been added.") at ... Clear. I'll create a bug test for this and notify you. Ok. Thank you! Any news on this issue? Do you need a sample? Sorry, it's still under investigation - we need ~ 2 more days, since there are lot of similar work in queue. The sample isn't necessary. Issue 841 is created. Done. Full explanation will follow up soon. Is this fixed in build 6600? Yes, it is - sorry, I forgot to mention this. Today I'll publish a sample showing what must be done to describe such changes. I still can't get it to work. Upgrader code: hintSet.Add(new RenameTypeHint("B", typeof(A))); If I remove the type I get this exception: System.ArgumentException occurred Message=An item with the same key has already been added in Xtensive.Storage.Building.SchemaComparer.Compare If I add the attribute [Recycled] I get: System.ArgumentException occurred Message=An item with the same key has already been added in Xtensive.Storage.Upgrade.HintGenerator.RewriteGenericTypeHints I you need the full stack, ask me : I can't post it here. Please see the answer I just posted. |