예제 #1
0
        protected unsafe void SetByteArrayValue(string propertyName, byte[] value)
        {
            Debug.Assert(_realm != null, "Object is not managed, but managed access was attempted");

            if (!_realm.IsInTransaction)
            {
                throw new RealmOutsideTransactionException("Cannot set values outside transaction");
            }

            if (value == null)
            {
                NativeTable.set_null(_metadata.Table, _metadata.ColumnIndices[propertyName], (IntPtr)_rowHandle.RowIndex);
            }
            else if (value.Length == 0)
            {
                // empty byte arrays are expressed in terms of a BinaryData object with a dummy pointer and zero size
                // that's how core differentiates between empty and null buffers
                NativeTable.set_binary(_metadata.Table, _metadata.ColumnIndices[propertyName], (IntPtr)_rowHandle.RowIndex, (IntPtr)0x1, IntPtr.Zero);
            }
            else
            {
                fixed(byte *buffer = value)
                {
                    NativeTable.set_binary(_metadata.Table, _metadata.ColumnIndices[propertyName], (IntPtr)_rowHandle.RowIndex, (IntPtr)buffer, (IntPtr)value.LongLength);
                }
            }
        }
예제 #2
0
        /// <summary>
        /// This realm will start managing a RealmObject which has been created as a standalone object.
        /// </summary>
        /// <typeparam name="T">The Type T must not only be a RealmObject but also have been processd by the Fody weaver, so it has persistent properties.</typeparam>
        /// <param name="obj">Must be a standalone object, null not allowed.</param>
        /// <exception cref="RealmOutsideTransactionException">If you invoke this when there is no write Transaction active on the realm.</exception>
        /// <exception cref="RealmObjectAlreadyManagedByRealmException">You can't manage the same object twice. This exception is thrown, rather than silently detecting the mistake, to help you debug your code</exception>
        /// <exception cref="RealmObjectManagedByAnotherRealmException">You can't manage an object with more than one realm</exception>
        public void Manage <T>(T obj) where T : RealmObject
        {
            if (obj == null)
            {
                throw new ArgumentNullException(nameof(obj));
            }

            if (obj.IsManaged)
            {
                if (obj.Realm.SharedRealmHandle == this.SharedRealmHandle)
                {
                    throw new RealmObjectAlreadyManagedByRealmException("The object is already managed by this realm");
                }

                throw new RealmObjectManagedByAnotherRealmException("Cannot start to manage an object with a realm when it's already managed by another realm");
            }


            if (!IsInTransaction)
            {
                throw new RealmOutsideTransactionException("Cannot start managing a Realm object outside write transactions");
            }

            var tableHandle = Metadata[typeof(T)].Table;

            var rowPtr    = NativeTable.add_empty_row(tableHandle);
            var rowHandle = CreateRowHandle(rowPtr, SharedRealmHandle);

            obj._Manage(this, rowHandle);
            obj._CopyDataFromBackingFieldsToRow();
        }
예제 #3
0
        private RealmObject.Metadata CreateRealmObjectMetadata(Type realmObjectType)
        {
            var table    = this.GetTable(realmObjectType);
            var wovenAtt = realmObjectType.GetCustomAttribute <WovenAttribute>();

            if (wovenAtt == null)
            {
                throw new RealmException($"Fody not properly installed. {realmObjectType.FullName} is a RealmObject but has not been woven.");
            }
            var helper     = (Weaving.IRealmObjectHelper)Activator.CreateInstance(wovenAtt.HelperType);
            var properties = realmObjectType.GetProperties(BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.NonPublic | BindingFlags.Public)
                             .Where(p => p.GetCustomAttributes(false).OfType <WovenPropertyAttribute>().Any())
                             .Select(p =>
            {
                var mapTo = p.GetCustomAttributes(false).OfType <MapToAttribute>().SingleOrDefault();
                if (mapTo != null)
                {
                    return(mapTo.Mapping);
                }

                return(p.Name);
            })
                             .ToDictionary(name => name, name => NativeTable.get_column_index(table, name, (IntPtr)name.Length));

            return(new RealmObject.Metadata
            {
                Table = table,
                Helper = helper,
                ColumnIndices = properties
            });
        }
예제 #4
0
        protected bool GetBooleanValue(string propertyName)
        {
            Debug.Assert(_realm != null, "Object is not managed, but managed access was attempted");

            var rowIndex = _rowHandle.RowIndex;

            return(MarshalHelpers.IntPtrToBool(NativeTable.get_bool(_metadata.Table, _metadata.ColumnIndices[propertyName], (IntPtr)rowIndex)));
        }
예제 #5
0
        protected double GetDoubleValue(string propertyName)
        {
            Debug.Assert(_realm != null, "Object is not managed, but managed access was attempted");

            var rowIndex = _rowHandle.RowIndex;

            return(NativeTable.get_double(_metadata.Table, _metadata.ColumnIndices[propertyName], (IntPtr)rowIndex));
        }
예제 #6
0
        public static double?GetNullableDouble(TableHandle tableHandle, IntPtr columnIndex, IntPtr rowIndex)
        {
            NativeException nativeException;
            double          value;
            var             hasValue = MarshalHelpers.IntPtrToBool(NativeTable.get_nullable_double(tableHandle, columnIndex, rowIndex, out value, out nativeException));

            nativeException.ThrowIfNecessary();
            return(hasValue ? value : (double?)null);
        }
예제 #7
0
        public static bool?GetNullableBoolean(TableHandle tableHandle, IntPtr columnIndex, IntPtr rowIndex)
        {
            NativeException nativeException;
            IntPtr          value;
            var             hasValue = MarshalHelpers.IntPtrToBool(NativeTable.get_nullable_bool(tableHandle, columnIndex, rowIndex, out value, out nativeException));

            nativeException.ThrowIfNecessary();
            return(hasValue ? MarshalHelpers.IntPtrToBool(value) : (bool?)null);
        }
예제 #8
0
        protected T GetObjectValue <T>(string propertyName) where T : RealmObject
        {
            Debug.Assert(_realm != null, "Object is not managed, but managed access was attempted");

            var rowIndex     = _rowHandle.RowIndex;
            var linkedRowPtr = NativeTable.get_link(_metadata.Table, _metadata.ColumnIndices[propertyName], (IntPtr)rowIndex);

            return((T)MakeRealmObject(typeof(T), linkedRowPtr));
        }
예제 #9
0
        protected DateTimeOffset GetDateTimeOffsetValue(string propertyName)
        {
            Debug.Assert(_realm != null, "Object is not managed, but managed access was attempted");

            var rowIndex = _rowHandle.RowIndex;

            var unixTimeSeconds = NativeTable.get_datetime_seconds(_metadata.Table, _metadata.ColumnIndices[propertyName], (IntPtr)rowIndex);

            return(DateTimeOffsetExtensions.FromUnixTimeSeconds(unixTimeSeconds));
        }
예제 #10
0
        protected int GetInt32Value(string propertyName)
        {
            Debug.Assert(_realm != null, "Object is not managed, but managed access was attempted");

            var rowIndex = _rowHandle.RowIndex;

            var value = NativeTable.get_int64(_metadata.Table, _metadata.ColumnIndices[propertyName], (IntPtr)rowIndex);

            return((int)value);
        }
예제 #11
0
        public static DateTimeOffset?GetNullableDateTimeOffset(TableHandle tableHandle, IntPtr columnIndex,
                                                               IntPtr rowIndex)
        {
            NativeException nativeException;
            long            ticks;
            var             hasValue = MarshalHelpers.IntPtrToBool(NativeTable.get_nullable_timestamp_ticks(tableHandle, columnIndex, rowIndex, out ticks, out nativeException));

            nativeException.ThrowIfNecessary();
            return(hasValue ? new DateTimeOffset(ticks, TimeSpan.Zero) : (DateTimeOffset?)null);
        }
예제 #12
0
        protected string GetStringValue(string propertyName)
        {
            Debug.Assert(_realm != null, "Object is not managed, but managed access was attempted");

            var rowIndex   = _rowHandle.RowIndex;
            var badUTF8msg = $"Corrupted string UTF8 in {propertyName}";

            int bufferSizeNeededChars = 128;

            // First alloc this thread
            if (_realm.stringGetBuffer == IntPtr.Zero)    // first get of a string in this Realm
            {
                _realm.stringGetBuffer    = Marshal.AllocHGlobal((IntPtr)(bufferSizeNeededChars * sizeof(char)));
                _realm.stringGetBufferLen = bufferSizeNeededChars;
            }

            bool isNull = false;

            // try to read
            int bytesRead = (int)NativeTable.get_string(_metadata.Table, _metadata.ColumnIndices[propertyName], (IntPtr)rowIndex, _realm.stringGetBuffer,
                                                        (IntPtr)_realm.stringGetBufferLen, out isNull);

            if (bytesRead == -1)
            {
                // bad UTF-8 data unable to transcode, vastly unlikely error but could be corrupt file
                throw new RealmInvalidDatabaseException(badUTF8msg);
            }
            if (bytesRead > _realm.stringGetBufferLen)  // need a bigger buffer
            {
                Marshal.FreeHGlobal(_realm.stringGetBuffer);
                _realm.stringGetBuffer    = Marshal.AllocHGlobal((IntPtr)(bytesRead * sizeof(char)));
                _realm.stringGetBufferLen = bytesRead;
                // try to read with big buffer
                bytesRead = (int)NativeTable.get_string(_metadata.Table, _metadata.ColumnIndices[propertyName], (IntPtr)rowIndex, _realm.stringGetBuffer,
                                                        (IntPtr)_realm.stringGetBufferLen, out isNull);
                if (bytesRead == -1)  // bad UTF-8 in full string
                {
                    throw new RealmInvalidDatabaseException(badUTF8msg);
                }
                Debug.Assert(bytesRead <= _realm.stringGetBufferLen);
            }  // needed re-read with expanded buffer

            if (bytesRead == 0)
            {
                if (isNull)
                {
                    return(null);
                }

                return("");
            }

            return(Marshal.PtrToStringUni(_realm.stringGetBuffer, bytesRead));
            // leaving buffer sitting allocated for quick reuse next time we read a string
        } // GetStringValue
예제 #13
0
        protected DateTimeOffset?GetNullableDateTimeOffsetValue(string propertyName)
        {
            Debug.Assert(_realm != null, "Object is not managed, but managed access was attempted");

            var rowIndex = _rowHandle.RowIndex;

            long unixTimeSeconds = 0;
            var  hasValue        = MarshalHelpers.IntPtrToBool(NativeTable.get_nullable_datetime_seconds(_metadata.Table, _metadata.ColumnIndices[propertyName], (IntPtr)rowIndex, ref unixTimeSeconds));

            return(hasValue ? DateTimeOffsetExtensions.FromUnixTimeSeconds(unixTimeSeconds) : (DateTimeOffset?)null);
        }
예제 #14
0
        protected bool?GetNullableBooleanValue(string propertyName)
        {
            Debug.Assert(_realm != null, "Object is not managed, but managed access was attempted");

            var rowIndex = _rowHandle.RowIndex;

            var retVal   = IntPtr.Zero;
            var hasValue = MarshalHelpers.IntPtrToBool(NativeTable.get_nullable_bool(_metadata.Table, _metadata.ColumnIndices[propertyName], (IntPtr)rowIndex, ref retVal));

            return(hasValue ? MarshalHelpers.IntPtrToBool(retVal) : (bool?)null);
        }
예제 #15
0
        protected double?GetNullableDoubleValue(string propertyName)
        {
            Debug.Assert(_realm != null, "Object is not managed, but managed access was attempted");

            var rowIndex = _rowHandle.RowIndex;

            var retVal   = 0.0d;
            var hasValue = MarshalHelpers.IntPtrToBool(NativeTable.get_nullable_double(_metadata.Table, _metadata.ColumnIndices[propertyName], (IntPtr)rowIndex, ref retVal));

            return(hasValue ? retVal : (double?)null);
        }
예제 #16
0
        public static T GetObject <T>(Realm realm, TableHandle table, IntPtr columnIndex, IntPtr rowIndex, string objectType) where T : RealmObject
        {
            var linkedRowPtr = NativeTable.GetLink(table, columnIndex, rowIndex);

            if (linkedRowPtr == IntPtr.Zero)
            {
                return(null);
            }

            return((T)realm.MakeObjectForRow(objectType, linkedRowPtr));
        }
예제 #17
0
        /// <summary>
        /// Fast lookup of an object for dynamic use, from a class which has a PrimaryKey property.
        /// </summary>
        /// <param name="className">Name of class in dynamic situation.</param>
        /// <param name="id">Id to be matched exactly, same as an == search.</param>
        /// <returns>Null or an object matdhing the id.</returns>
        /// <exception cref="RealmClassLacksPrimaryKeyException">If the RealmObject class lacks an [PrimaryKey].</exception>
        public RealmObject ObjectForPrimaryKey(string className, string id)
        {
            var metadata = Metadata[className];
            var rowPtr   = NativeTable.RowForPrimaryKey(metadata.Table, metadata.PrimaryKeyColumnIndex, id);

            if (rowPtr == IntPtr.Zero)
            {
                return(null);
            }
            return(MakeObjectForRow(metadata, rowPtr));
        }
예제 #18
0
        /// <summary>
        /// Removes a persistent object from this realm, effectively deleting it.
        /// </summary>
        /// <param name="obj">Must be an object persisted in this realm.</param>
        /// <exception cref="RealmOutsideTransactionException">If you invoke this when there is no write Transaction active on the realm.</exception>
        /// <exception cref="System.ArgumentNullException">If you invoke this with a standalone object.</exception>
        public void Remove(RealmObject obj)
        {
            if (!IsInTransaction)
            {
                throw new RealmOutsideTransactionException("Cannot remove Realm object outside write transactions");
            }

            var tableHandle = Metadata[obj.GetType()].Table;

            NativeTable.remove_row(tableHandle, (RowHandle)obj.RowHandle);
        }
예제 #19
0
        protected void SetByteArrayValue(string propertyName, byte[] value)
        {
            Debug.Assert(_realm != null, "Object is not managed, but managed access was attempted");

            if (!_realm.IsInTransaction)
            {
                throw new RealmOutsideTransactionException("Cannot set values outside transaction");
            }

            NativeTable.SetByteArray(_metadata.Table, _metadata.ColumnIndices[propertyName], _rowHandle.RowIndex, value);
        }
예제 #20
0
        /// <summary>
        /// Fast lookup of an object from a class which has a PrimaryKey property.
        /// </summary>
        /// <typeparam name="T">The Type T must be a RealmObject.</typeparam>
        /// <param name="id">Id to be matched exactly, same as an == search.</param>
        /// <returns>Null or an object matdhing the id.</returns>
        /// <exception cref="RealmClassLacksPrimaryKeyException">If the RealmObject class T lacks an [PrimaryKey].</exception>
        public T ObjectForPrimaryKey <T>(string id) where T : RealmObject
        {
            var metadata = Metadata[typeof(T).Name];
            var rowPtr   = NativeTable.RowForPrimaryKey(metadata.Table, metadata.PrimaryKeyColumnIndex, id);

            if (rowPtr == IntPtr.Zero)
            {
                return(null);
            }
            return((T)MakeObjectForRow(metadata, rowPtr));
        }
예제 #21
0
        protected void SetBooleanValue(string propertyName, bool value)
        {
            Debug.Assert(_realm != null, "Object is not managed, but managed access was attempted");

            if (!_realm.IsInTransaction)
            {
                throw new RealmOutsideTransactionException("Cannot set values outside transaction");
            }

            var rowIndex = _rowHandle.RowIndex;

            NativeTable.set_bool(_metadata.Table, _metadata.ColumnIndices[propertyName], (IntPtr)rowIndex, MarshalHelpers.BoolToIntPtr(value));
        }
예제 #22
0
        protected void SetInt64ValueUnique(string propertyName, long value)
        {
            Debug.Assert(_realm != null, "Object is not managed, but managed access was attempted");

            if (!_realm.IsInTransaction)
            {
                throw new RealmOutsideTransactionException("Cannot set values outside transaction");
            }

            var rowIndex = _rowHandle.RowIndex;

            NativeTable.set_int64_unique(_metadata.Table, _metadata.ColumnIndices[propertyName], (IntPtr)rowIndex, value);
        }
예제 #23
0
        /// <summary>
        /// Fast count all objects of a given class, or in a RealmResults after casting.
        /// </summary>
        /// <remarks>
        /// Resolves to this method instead of the LINQ static extension <c>Count<T>(this IEnumerable<T>)</c>, when used directly on Realm.All.
        /// <br>
        /// if someone CASTS a RealmResults<T> variable from a Where call to
        /// a RealmResults<T> they change its compile-time type from IQueryable<blah> (which invokes LINQ)
        /// to RealmResults<T> and thus ends up here.
        /// </remarks>
        /// <returns>Count of all objects in a class or in the results of a search, without instantiating them.</returns>
        public int Count()
        {
            if (_allRecords)
            {
                // use the type captured at build based on generic T
                var tableHandle = _realm.Metadata [ObjectSchema.Name].Table;
                return((int)NativeTable.CountAll(tableHandle));
            }

            // normally we would  be in RealmQRealmResultsr.VisitMethodCall, not here
            // however, casting as described in the remarks above can cause this method to be invoked.
            // as in the unit test CountFoundWithCasting
            return((int)ResultsHandle.Count());
        }
예제 #24
0
 public static void SetObject(Realm realm, TableHandle table, IntPtr columnIndex, IntPtr rowIndex, RealmObject @object)
 {
     if (@object == null)
     {
         NativeTable.ClearLink(table, columnIndex, rowIndex);
     }
     else
     {
         if ([email protected])
         {
             realm.Manage(@object);
         }
         NativeTable.SetLink(table, columnIndex, rowIndex, @object.RowHandle.RowIndex);
     }
 }
예제 #25
0
        protected void SetDateTimeOffsetValue(string propertyName, DateTimeOffset value)
        {
            Debug.Assert(_realm != null, "Object is not managed, but managed access was attempted");

            if (!_realm.IsInTransaction)
            {
                throw new RealmOutsideTransactionException("Cannot set values outside transaction");
            }

            var rowIndex = _rowHandle.RowIndex;

            var marshalledValue = value.ToUnixTimeSeconds();

            NativeTable.set_datetime_seconds(_metadata.Table, _metadata.ColumnIndices[propertyName], (IntPtr)rowIndex, marshalledValue);
        }
예제 #26
0
        protected byte[] GetByteArrayValue(string propertyName)
        {
            Debug.Assert(_realm != null, "Object is not managed, but managed access was attempted");

            int    bufferSize;
            IntPtr buffer;

            if (NativeTable.get_binary(_metadata.Table, _metadata.ColumnIndices[propertyName], (IntPtr)_rowHandle.RowIndex, out buffer, out bufferSize) != IntPtr.Zero)
            {
                var bytes = new byte[bufferSize];
                Marshal.Copy(buffer, bytes, 0, bufferSize);
                return(bytes);
            }

            return(null);
        }
예제 #27
0
        /// <summary>
        /// Fast count all objects of a given class.
        /// </summary>
        /// <remarks>
        /// Resolves to this method instead of the LINQ static extension <c>Count&lt;T&gt;(this IEnumerable&lt;T&gt;)</c>, when used directly on Realm.All.
        /// </remarks>
        public int Count()
        {
            if (_allRecords)
            {
                // use the type captured at build based on generic T
                var tableHandle = _realm.Metadata[ElementType].Table;
                return((int)NativeTable.count_all(tableHandle));
            }

            // normally we would  be in RealmQRealmResultsr.VisitMethodCall, not here
            // however, if someone CASTS a RealmResults<blah> variable from a Where call to
            // a RealmResults<blah> they change its compile-time type from IQueryable<blah> (which invokes LINQ)
            // to RealmResults<blah> and thus ends up here.
            // as in the unit test CountFoundWithCasting
            return((int)NativeResults.count(ResultsHandle));
        }
예제 #28
0
        private QueryHandle CreateQuery(Schema.ObjectSchema elementType)
        {
            var tableHandle = _realm.Metadata[elementType.Name].Table;
            var queryHandle = tableHandle.TableWhere();

            //At this point sh is invalid due to its handle being uninitialized, but the root is set correctly
            //a finalize at this point will not leak anything and the handle will not do anything

            //now, set the TableView handle...
            RuntimeHelpers.PrepareConstrainedRegions();//the following finally will run with no out-of-band exceptions
            try { }
            finally
            {
                queryHandle.SetHandle(NativeTable.Where(tableHandle));
            }//at this point we have atomically acquired a handle and also set the root correctly so it can be unbound correctly
            return(queryHandle);
        }
예제 #29
0
        internal LinkListHandle TableLinkList(IntPtr columnIndex, IntPtr rowIndex)
        {
            var listHandle = RootedLinkListHandle();

            //At this point sh is invalid due to its handle being uninitialized, but the root is set correctly
            //a finalize at this point will not leak anything and the handle will not do anything

            //now, set the TableView handle...
            RuntimeHelpers.PrepareConstrainedRegions();//the following finally will run with no out-of-band exceptions
            try
            { }
            finally
            {
                listHandle.SetHandle(NativeTable.GetLinklist(this, columnIndex, rowIndex));
            }//at this point we have atomically acquired a handle and also set the root correctly so it can be unbound correctly
            return(listHandle);
        }
예제 #30
0
        internal QueryHandle TableWhere()
        {
            var queryHandle = RootedQueryHandle();

            //At this point sh is invalid due to its handle being uninitialized, but the root is set correctly
            //a finalize at this point will not leak anything and the handle will not do anything

            //now, set the TableView handle...
            RuntimeHelpers.PrepareConstrainedRegions();//the following finally will run with no out-of-band exceptions
            try
            { }
            finally
            {
                queryHandle.SetHandle(NativeTable.Where(this));
            }//at this point we have atomically acquired a handle and also set the root correctly so it can be unbound correctly
            return(queryHandle);
        }