From b8e4aaaf63898ba7f0499be1b85eec68ee9ff08a Mon Sep 17 00:00:00 2001 From: Nikola Irinchev Date: Fri, 22 Jun 2018 13:36:21 +0200 Subject: [PATCH] Don't throw an exception when adding an object to a different instance of the same on-disk Realm --- CHANGELOG.md | 3 + Realm/Realm/Realm.cs | 72 ++++++-------------- Tests/Tests.Shared/ObjectIntegrationTests.cs | 14 ++++ 3 files changed, 36 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 26ff46b020..d2958338b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ ### Bug fixes - `WriteAsync` will no longer perform a synchronous `Refresh` on the main thread. ([#1729](https://github.com/realm/realm-dotnet/pull/1729)) +- Trying to add a managed Realm Object to a different instance of the same on-disk Realm will no +longer throw an exception. ### Breaking Changes - `SyncConfiguration` is now deprecated and will be removed in a future version. Two new configuration @@ -13,6 +15,7 @@ and [FullSyncConfiguration](https://docs.realm.io/platform/using-synced-realms/s If you were using a `SyncConfiguration` with `IsPartial = true`, then change your code to use `QueryBasedSyncConfiguration`. Similarly, if `IsPartial` was not set or was set to `false`, use `FullSyncConfiguration`. + x.y.z (TBD) ------------------ diff --git a/Realm/Realm/Realm.cs b/Realm/Realm/Realm.cs index 855b9ba797..39b8b42ff6 100644 --- a/Realm/Realm/Realm.cs +++ b/Realm/Realm/Realm.cs @@ -26,6 +26,7 @@ using System.Threading; using System.Threading.Tasks; using Realms.Exceptions; +using Realms.Helpers; using Realms.Native; using Realms.Schema; @@ -118,10 +119,7 @@ public static Task GetInstanceAsync(RealmConfigurationBase config = null) internal static Realm GetInstance(RealmConfigurationBase config, RealmSchema schema) { - if (config == null) - { - throw new ArgumentNullException(nameof(config)); - } + Argument.NotNull(config, nameof(config)); if (schema == null) { @@ -389,7 +387,9 @@ public bool IsSameInstance(Realm other) { ThrowIfDisposed(); - return SharedRealmHandle.IsSameInstance(other.SharedRealmHandle); + Argument.NotNull(other, nameof(other)); + + return SharedRealmHandle == other.SharedRealmHandle || SharedRealmHandle.IsSameInstance(other.SharedRealmHandle); } /// @@ -439,10 +439,7 @@ public dynamic CreateObject(string className, object primaryKey) private RealmObject CreateObject(string className, object primaryKey, out RealmObject.Metadata metadata) { - if (!Metadata.TryGetValue(className, out metadata)) - { - throw new ArgumentException($"The class {className} is not in the limited set of classes for this realm"); - } + Argument.Ensure(Metadata.TryGetValue(className, out metadata), $"The class {className} is not in the limited set of classes for this realm", nameof(className)); var result = metadata.Helper.CreateInstance(); @@ -541,19 +538,12 @@ public RealmObject Add(RealmObject obj, bool update = false) private void AddInternal(RealmObject obj, Type objectType, bool update) { - if (obj == null) - { - throw new ArgumentNullException(nameof(obj)); - } - - if (objectType == null) - { - throw new ArgumentNullException(nameof(objectType)); - } + Argument.NotNull(obj, nameof(obj)); + Argument.NotNull(objectType, nameof(objectType)); if (obj.IsManaged) { - if (obj.Realm.SharedRealmHandle == this.SharedRealmHandle) + if (IsSameInstance(obj.Realm)) { // Already managed by this realm, so nothing to do. return; @@ -563,10 +553,7 @@ private void AddInternal(RealmObject obj, Type objectType, bool update) } var objectName = objectType.GetTypeInfo().GetMappedOrOriginalName(); - if (!Metadata.TryGetValue(objectName, out var metadata)) - { - throw new ArgumentException($"The class {objectType.Name} is not in the limited set of classes for this realm"); - } + Argument.Ensure(Metadata.TryGetValue(objectName, out var metadata), $"The class {objectType.Name} is not in the limited set of classes for this realm", nameof(objectType)); ObjectHandle objectHandle; bool isNew; @@ -686,10 +673,7 @@ public Task WriteAsync(Action action) // Can't use async/await due to mono inliner bugs ThrowIfDisposed(); - if (action == null) - { - throw new ArgumentNullException(nameof(action)); - } + Argument.NotNull(action, nameof(action)); // If we are on UI thread will be set but often also set on long-lived workers to use Post back to UI thread. if (SynchronizationContext.Current != null) @@ -777,10 +761,9 @@ void handler(object sender, EventArgs e) ThrowIfDisposed(); var type = typeof(T); - if (!Metadata.TryGetValue(type.GetTypeInfo().GetMappedOrOriginalName(), out var metadata) || metadata.Schema.Type.AsType() != type) - { - throw new ArgumentException($"The class {type.Name} is not in the limited set of classes for this realm"); - } + Argument.Ensure( + Metadata.TryGetValue(type.GetTypeInfo().GetMappedOrOriginalName(), out var metadata) && metadata.Schema.Type.AsType() == type, + $"The class {type.Name} is not in the limited set of classes for this realm", nameof(T)); return new RealmResults(this, metadata); } @@ -795,10 +778,7 @@ public IQueryable All(string className) { ThrowIfDisposed(); - if (!Metadata.TryGetValue(className, out var metadata)) - { - throw new ArgumentException($"The class {className} is not in the limited set of classes for this realm"); - } + Argument.Ensure(Metadata.TryGetValue(className, out var metadata), $"The class {className} is not in the limited set of classes for this realm", nameof(className)); return new RealmResults(this, metadata); } @@ -977,15 +957,8 @@ public void Remove(RealmObject obj) { ThrowIfDisposed(); - if (obj == null) - { - throw new ArgumentNullException(nameof(obj)); - } - - if (!obj.IsManaged) - { - throw new ArgumentException("Object is not managed by Realm, so it cannot be removed.", nameof(obj)); - } + Argument.NotNull(obj, nameof(obj)); + Argument.Ensure(obj.IsManaged, "Object is not managed by Realm, so it cannot be removed.", nameof(obj)); obj.ObjectHandle.RemoveFromRealm(SharedRealmHandle); } @@ -1006,15 +979,8 @@ public void Remove(RealmObject obj) { ThrowIfDisposed(); - if (range == null) - { - throw new ArgumentNullException(nameof(range)); - } - - if (!(range is RealmResults)) - { - throw new ArgumentException("range should be the return value of .All or a LINQ query applied to it.", nameof(range)); - } + Argument.NotNull(range, nameof(range)); + Argument.Ensure(range is RealmResults, "range should be the return value of .All or a LINQ query applied to it.", nameof(range)); var results = (RealmResults)range; results.ResultsHandle.Clear(SharedRealmHandle); diff --git a/Tests/Tests.Shared/ObjectIntegrationTests.cs b/Tests/Tests.Shared/ObjectIntegrationTests.cs index 6fb0c1a178..e33d7a1ed6 100644 --- a/Tests/Tests.Shared/ObjectIntegrationTests.cs +++ b/Tests/Tests.Shared/ObjectIntegrationTests.cs @@ -183,6 +183,20 @@ public void AddAnObjectFromAnotherRealmShouldFail() } } + [Test] + public void AddAnObject_WhenRealmIsDifferentInstanceOnSameThread_ShouldSucceed() + { + var firstObject = new IntPrimaryKeyWithValueObject(); + _realm.Write(() => _realm.Add(firstObject)); + + using (var realm2 = Realm.GetInstance(_realm.Config)) + { + Assert.That(firstObject.IsManaged); + Assert.That(realm2.IsSameInstance(firstObject.Realm)); + realm2.Write(() => realm2.Add(firstObject)); + } + } + [Test] public void SetPropertyOutsideTransactionShouldFail() {