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

Don't throw an exception when adding an object to a different instanc… #1753

Merged
merged 1 commit into from
Jun 22, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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