Skip to content

Commit

Permalink
Don't throw an exception when adding an object to a different instanc…
Browse files Browse the repository at this point in the history
…e of the same on-disk Realm (#1753)
  • Loading branch information
nirinchev committed Jun 22, 2018
1 parent 85f5e77 commit 5d6a7f5
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 53 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
------------------

Expand Down
72 changes: 19 additions & 53 deletions Realm/Realm/Realm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
using System.Threading;
using System.Threading.Tasks;
using Realms.Exceptions;
using Realms.Helpers;
using Realms.Native;
using Realms.Schema;

Expand Down Expand Up @@ -118,10 +119,7 @@ public static Task<Realm> 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)
{
Expand Down Expand Up @@ -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);
}

/// <inheritdoc/>
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -686,10 +673,7 @@ public Task WriteAsync(Action<Realm> 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)
Expand Down Expand Up @@ -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<T>(this, metadata);
}
Expand All @@ -795,10 +778,7 @@ public IQueryable<dynamic> 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<RealmObject>(this, metadata);
}
Expand Down Expand Up @@ -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);
}
Expand All @@ -1006,15 +979,8 @@ public void Remove(RealmObject obj)
{
ThrowIfDisposed();

if (range == null)
{
throw new ArgumentNullException(nameof(range));
}

if (!(range is RealmResults<T>))
{
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<T>, "range should be the return value of .All or a LINQ query applied to it.", nameof(range));

var results = (RealmResults<T>)range;
results.ResultsHandle.Clear(SharedRealmHandle);
Expand Down
14 changes: 14 additions & 0 deletions Tests/Tests.Shared/ObjectIntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down

0 comments on commit 5d6a7f5

Please sign in to comment.