Skip to content
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

Error when trying to migrate IList data type with DynamicApi.GetList #3597

Closed
Scorter opened this issue May 6, 2024 · 6 comments · Fixed by #3601
Closed

Error when trying to migrate IList data type with DynamicApi.GetList #3597

Scorter opened this issue May 6, 2024 · 6 comments · Fixed by #3601

Comments

@Scorter
Copy link

Scorter commented May 6, 2024

What happened?

I'm migrating data that was previously "float?" and IList<float?" to the type "string" and "IList". I am attaching the code that performs this migration, and everything goes well when I give a DynamicApi.GetList in an IEmbeddedObject, however, when I call a DynamicApi.GetList in a "float?" gives the error "KeyNotFoundException: The given key '' was not present in the dictionary". him being the "float?" type. The error only happens when I try to call a GetList in the "MeasuredValues" field, the rest of the code works fine and performs the correct conversion. Does anyone have an idea what I might be doing wrong? See the error that appears:

image

See how MeasuredValues ​​is in the database, it appears in the scope as List but it is a List<float?>, I believe this is a bug in the realm, but I guarantee that in the code we are saving it as IList<float?>.

image

I'm attaching a drive with the old bank (the bank that tries to get "MeasuredValues") in case it helps with anything. Link drive :
LinkDrive

Repro steps

  1. Save an object in the database with the field type "IList<float?>
  2. Perform a database migration by calling GetList from an "Ilist<float?">

The error occurs exactly on this line:
image

Version

.NET Framework

What Atlas Services are you using?

Local Database only

What type of application is this?

Unity

Client OS and version

Unity

Code snippets

if (oldSchemaVersion < 2)
{
    var oldOrders = migration.OldRealm.DynamicApi.All("OrderServiceEntity");
    var newOrders = migration.NewRealm.All<OrderServiceEntity>();

    for (int i = 0; i < newOrders.Count(); i++)
    {
        var oldOrder = oldOrders.ElementAt(i);
        var newOrder = newOrders.ElementAt(i);

        var oldCalibration = oldOrder.DynamicApi.Get<IEmbeddedObject>("Calibration");
        var newCalibration = newOrder.Calibration;

        if (oldCalibration != null)
        {
            for (int j = 0; j < oldCalibration.DynamicApi.GetList<IEmbeddedObject>("TablePages").Count; j++)
            {
                IEmbeddedObject oldPage = oldCalibration.DynamicApi.GetList<IEmbeddedObject>("TablePages")[j];
                var newPage = newCalibration.TablePages[j];

                for (int k = 0; k < oldPage.DynamicApi.GetList<IEmbeddedObject>("Rows").Count; k++)
                {
                    UnityEngine.Debug.LogError(k);
                    var oldRow = oldPage.DynamicApi.GetList<IEmbeddedObject>("Rows")[k];
                    var newRow = newPage.Rows[k];

                    // Convertendo o campo Nominal
                    var oldNominal = oldRow.DynamicApi.Get<float?>("Nominal");
                    newRow.Nominal = oldNominal.HasValue ? oldNominal.Value.ToString() : null;

                    // The error is here on this line:
                    IList<float?> oldMeasuredValues = oldRow.DynamicApi.GetList<float?>("MeasuredValues");

                    var newMeasuredValues = new List<string?>();
                    foreach (var value in oldMeasuredValues)
                    {
                        newMeasuredValues.Add(value.HasValue ? value.Value.ToString() : null);
                    }

                    newRow.MeasuredValues.Clear();
                    foreach (var newMeasured in newMeasuredValues)
                    {
                        newRow.MeasuredValues.Add(newMeasured);
                    }
                }
            }
        }
    }
}

Stacktrace of the exception/crash you're getting

KeyNotFoundException: The given key '' was not present in the dictionary.
System.Collections.Generic.Dictionary`2[TKey,TValue].get_Item (TKey key) (at <51ee0c51c90047b488b10b1b78b365d8>:0)
Realms.Realm+RealmMetadata.get_Item (System.String objectType) (at <20c8551e199242abadc6d7b62871711c>:0)
Realms.ObjectHandle.GetList[T] (Realms.Realm realm, System.String propertyName, Realms.Metadata metadata, System.String objectType) (at <20c8551e199242abadc6d7b62871711c>:0)
Realms.DynamicObjectApi.GetList[T] (System.String propertyName) (at <20c8551e199242abadc6d7b62871711c>:0)
Ark.API.CMMS.Database.CmmsDatabase.MigrationCallBack (Realms.Migration migration, System.UInt64 oldSchemaVersion) (at Assets/Scripts/Api/CMMS/Database/CmmsDatabase.cs:174)
Realms.SharedRealmHandle.OnMigration (System.IntPtr oldRealmPtr, System.IntPtr newRealmPtr, System.IntPtr migrationSchema, Realms.Native.Schema oldSchema, System.UInt64 schemaVersion, System.IntPtr managedConfigHandle) (at <20c8551e199242abadc6d7b62871711c>:0)
Rethrow as AggregateException: Exception occurred in a Realm.MigrationCallback callback. (The given key '' was not present in the dictionary.)
Realms.NativeException.ThrowIfNecessary () (at <20c8551e199242abadc6d7b62871711c>:0)
Realms.SharedRealmHandle.Open (Realms.Native.Configuration configuration) (at <20c8551e199242abadc6d7b62871711c>:0)
Realms.RealmConfiguration.CreateHandle (Realms.Native.Configuration& configuration) (at <20c8551e199242abadc6d7b62871711c>:0)
Realms.RealmConfiguration+<>c__DisplayClass29_0.<CreateHandleAsync>b__1 (System.Threading.Tasks.Task _) (at <20c8551e199242abadc6d7b62871711c>:0)
System.Threading.Tasks.ContinuationResultTaskFromTask`1[TResult].InnerInvoke () (at <51ee0c51c90047b488b10b1b78b365d8>:0)
System.Threading.Tasks.Task.Execute () (at <51ee0c51c90047b488b10b1b78b365d8>:0)
--- End of stack trace from previous location where exception was thrown ---
Realms.RealmConfigurationBase.CreateRealmAsync (System.Threading.CancellationToken cancellationToken) (at <20c8551e199242abadc6d7b62871711c>:0)
Ark.Persistence.Database.RealmDatabase.InitAsync () (at

Relevant log output

No response

Copy link

sync-by-unito bot commented May 6, 2024

➤ PM Bot commented:

Jira ticket: RNET-1143

@papafe
Copy link
Contributor

papafe commented May 7, 2024

Hi @Scorter, thanks for reporting this.
Would it be possible for you to post here your models? If you prefer not to make them public we can figure something out.

@Scorter
Copy link
Author

Scorter commented May 7, 2024

Of course @papafe, first I will show you the old version.
Old version:

public partial class OrderServiceEntity : IRealmObject
{
    [PrimaryKey, Required]
    public string PrimaryKey { get; set; } // UserId_Id
    public int Id { get; set; }
    public int? Equipment { get; set; }
    public IList<OrderServiceProcedureEntity> Procedures { get; }
    public EditionEntity EditionValue { get; set; }
    public EditionEntity EditionOrigin { get; set; }
    public AttachmentsEntity Attachments { get; set; }
    public IList<WorkedHourEntity> WorkedHours { get; }
    public IList<ChecklistExecutionEntity> Checklists { get; }
    public CalibrationExecutionEntity Calibration { get; set; }
    public SignatureEntity SignatureValue { get; set; }
    public SignatureEntity SignatureOrigin { get; set; }
    public IList<int> StandardsValue { get; }
    public IList<int> StandardsOrigin { get; }
    public DateTimeOffset? ConclusionDate { get; internal set; }
    public string FinalizationSyncedState { get; set; }

    public bool HasDiverged<T>(T origin, T value) => !EqualityComparer<T>.Default.Equals(origin, value);
    public bool HasDiverged<T>(IList<T> origin, IList<T> value) => !value.SequenceEqual(origin);

}

    public partial class CalibrationExecutionEntity : IEmbeddedObject
    {
        /// <summary> <see cref="CMMS.CalibrationState"/> </summary>
        public string CalibrationState { get; set; }
        public int OrderServiceId { get; set; }
        public int Requestor { get; set; }
        public int Equipment { get; set; }

        // Dropdowns
        public int? ExecutingTechnician { get; set; }
        public int? TechnicalResponsable { get; set; }
        public int? Procedure { get; set; }

        // Date Fields
        public DateTimeOffset? CreationDate { get; set; }
        public DateTimeOffset? EmissionDate { get; set; }
        public DateTimeOffset? ValidityDate { get; set; }

        // Text Fields
        public string RequesterResponsible { get; set; } // Review this field
        public string Observations { get; set; }
        public string Local { get; set; }

        // Numeric Fields
        public float Temperature { get; set; }
        public float TemperatureUncertainty { get; set; }
        public float Humidity { get; set; }
        public float HumidityUncertainty { get; set; }
        public IList<CalibrationTablePageExecutionEntity> TablePages { get; }
    }

    public partial class CalibrationTablePageExecutionEntity : IEmbeddedObject
    {
        public string Title { get; set; }

        // Dropdown
        public int? Standard { get; set; }
        public int ReliabilityFactor { get; set; }
        public int? StandardCertificateTab { get; set; }
        public int AcceptanceCriteria { get; set; }

        // Numeric
        public float? StandardResolution { get; set; }
        public float? EquipmentResolution { get; set; }
        public float? UsageMin { get; set; }
        public float? UsageMax { get; set; }
        public float? CapacityMin { get; set; }
        public float? CapacityMax { get; set; }
        public string UnitOfMeasurement { get; set; }
        public float? MaxError { get; set; }
        public IList<CalibrationTableRowExecutionEntity> Rows { get; }
    }

    public partial class CalibrationTableRowExecutionEntity : IEmbeddedObject
    {
        public float? Nominal { get; set; }
        public IList<float?> MeasuredValues { get; }
    }

New version where is the migration to be done, transforming the "Nominal" and "MeasuredValues" fields from float? for string:

public partial class OrderServiceEntity : IRealmObject
{
    [PrimaryKey, Required]
    public string PrimaryKey { get; set; } // UserId_Id
    public int Id { get; set; }
    public int? Equipment { get; set; }
    public IList<OrderServiceProcedureEntity> Procedures { get; }
    public EditionEntity EditionValue { get; set; }
    public EditionEntity EditionOrigin { get; set; }
    public AttachmentsEntity Attachments { get; set; }
    public IList<WorkedHourEntity> WorkedHours { get; }
    public IList<ChecklistExecutionEntity> Checklists { get; }
    public CalibrationExecutionEntity Calibration { get; set; }
    public SignatureEntity SignatureValue { get; set; }
    public SignatureEntity SignatureOrigin { get; set; }
    public IList<int> StandardsValue { get; }
    public IList<int> StandardsOrigin { get; }
    public DateTimeOffset? ConclusionDate { get; internal set; }
    public string FinalizationSyncedState { get; set; }

    public bool HasDiverged<T>(T origin, T value) => !EqualityComparer<T>.Default.Equals(origin, value);
    public bool HasDiverged<T>(IList<T> origin, IList<T> value) => !value.SequenceEqual(origin);

}

    public partial class CalibrationExecutionEntity : IEmbeddedObject
    {
        /// <summary> <see cref="CMMS.CalibrationState"/> </summary>
        public string CalibrationState { get; set; }
        public int OrderServiceId { get; set; }
        public int Requestor { get; set; }
        public int Equipment { get; set; }

        // Dropdowns
        public int? ExecutingTechnician { get; set; }
        public int? TechnicalResponsable { get; set; }
        public int? Procedure { get; set; }

        // Date Fields
        public DateTimeOffset? CreationDate { get; set; }
        public DateTimeOffset? EmissionDate { get; set; }
        public DateTimeOffset? ValidityDate { get; set; }

        // Text Fields
        public string RequesterResponsible { get; set; } // Review this field
        public string Observations { get; set; }
        public string Local { get; set; }

        // Numeric Fields
        public float Temperature { get; set; }
        public float TemperatureUncertainty { get; set; }
        public float Humidity { get; set; }
        public float HumidityUncertainty { get; set; }
        public IList<CalibrationTablePageExecutionEntity> TablePages { get; }
    }

    public partial class CalibrationTablePageExecutionEntity : IEmbeddedObject
    {
        public string Title { get; set; }

        // Dropdown
        public int? Standard { get; set; }
        public int ReliabilityFactor { get; set; }
        public int? StandardCertificateTab { get; set; }
        public int AcceptanceCriteria { get; set; }

        // Numeric
        public string? StandardResolution { get; set; }
        public string? EquipmentResolution { get; set; }
        public float? UsageMin { get; set; }
        public float? UsageMax { get; set; }
        public float? CapacityMin { get; set; }
        public float? CapacityMax { get; set; }
        public string UnitOfMeasurement { get; set; }
        public float? MaxError { get; set; }
        public IList<CalibrationTableRowExecutionEntity> Rows { get; }
    }

    public partial class CalibrationTableRowExecutionEntity : IEmbeddedObject
    {
        public string Nominal { get; set; }
        public IList<string?> MeasuredValues { get; }
    }

Remembering that the error occurs specifically in the "MeasuredValues" field in the CalibrationTableRowExecutionEntity class. Thanks a lot for the help!

@nirinchev
Copy link
Member

I can reproduce this. Looking into it.

@Scorter
Copy link
Author

Scorter commented May 20, 2024

Hi @nirinchev, thanks for your help and solving this. Can you tell me when this pull request will be reviewed and this fix will be available?

@nirinchev
Copy link
Member

We had a company-wide hackathon last week, which is why there's been no movement on that PR. I expect it'll get reviewed and released at some point this week.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Jun 20, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants