/// <summary>
        /// Write a DeletedRecord in deleteIn dataset for the specified key
        /// instead of actually deleting the record. This ensures that
        /// a record in another dataset does not become visible during
        /// lookup in a sequence of datasets.
        ///
        /// To avoid an additional roundtrip to the data store, the delete
        /// marker is written even when the record does not exist.
        /// </summary>
        public override void Delete <TKey, TRecord>(TypedKey <TKey, TRecord> key, TemporalId deleteIn)
        {
            // Error message if data source is readonly or has CutoffTime set
            CheckNotReadOnly(deleteIn);

            // For pinned records, delete in root dataset irrespective of the value of saveTo
            if (IsPinned <TRecord>())
            {
                deleteIn = TemporalId.Empty;
            }

            // Create DeletedRecord with the specified key
            var record = new DeletedRecord {
                Key = key.Value
            };

            // Get collection
            var collection = GetOrCreateCollection <TRecord>();

            // This method guarantees that TemporalIds will be in strictly increasing
            // order for this instance of the data source class always, and across
            // all processes and machine if they are not created within the same
            // second.
            var recordId = CreateOrderedTemporalId();

            record.Id = recordId;

            // Assign dataset and then initialize, as the results of
            // initialization may depend on record.DataSet
            record.DataSet = deleteIn;

            // By design, insert will fail if TemporalId is not unique within the collection
            collection.BaseCollection.InsertOne(record);
        }
 /// <summary>
 /// Write a DeletedRecord for the dataset of the context and the specified
 /// key instead of actually deleting the record. This ensures that
 /// a record in another dataset does not become visible during
 /// lookup in a sequence of datasets.
 ///
 /// To avoid an additional roundtrip to the data store, the delete
 /// marker is written even when the record does not exist.
 /// </summary>
 public static void Delete <TKey, TRecord>(this Context obj, TypedKey <TKey, TRecord> key)
     where TKey : TypedKey <TKey, TRecord>, new()
     where TRecord : TypedRecord <TKey, TRecord>
 {
     // Delete in the dataset of the context
     obj.DataSource.Delete(key, obj.DataSet);
 }
        /// <summary>
        /// Load record by string key from the specified dataset or
        /// its list of imports. The lookup occurs first in descending
        /// order of dataset TemporalIds, and then in the descending
        /// order of record TemporalIds within the first dataset that
        /// has at least one record. Both dataset and record TemporalIds
        /// are ordered chronologically to one second resolution,
        /// and are unique within the database server or cluster.
        ///
        /// The root dataset has empty TemporalId value that is less
        /// than any other TemporalId value. Accordingly, the root
        /// dataset is the last one in the lookup order of datasets.
        ///
        /// The first record in this lookup order is returned, or null
        /// if no records are found or if DeletedRecord is the first
        /// record.
        ///
        /// Return null if there is no record for the specified TemporalId;
        /// however an exception will be thrown if the record exists but
        /// is not derived from TRecord.
        /// </summary>
        public override TRecord LoadOrNull <TKey, TRecord>(TypedKey <TKey, TRecord> key, TemporalId loadFrom)
        {
            // For pinned records, load from root dataset irrespective of the value of loadFrom
            if (IsPinned <TRecord>())
            {
                loadFrom = TemporalId.Empty;
            }

            // String value of the key in semicolon delimited format for use in the query
            string keyValue = key.ToString();

            // Look for exact match of the key
            var baseQueryable = GetOrCreateCollection <TRecord>()
                                .BaseCollection
                                .AsQueryable()
                                .Where(p => p.Key == keyValue);

            // Apply constraints on dataset and revision time
            var queryableWithFinalConstraints = ApplyFinalConstraints(baseQueryable, loadFrom);

            // Order by dataset and then by ID in descending order
            var orderedQueryable = queryableWithFinalConstraints
                                   .OrderByDescending(p => p.DataSet)
                                   .OrderByDescending(p => p.Id);

            // Result will be null if the record is not found
            var baseResult = orderedQueryable.FirstOrDefault();

            // Check not only for null but also for the DeletedRecord
            if (baseResult != null && !baseResult.Is <DeletedRecord>())
            {
                // Record is found but we do not yet know if it has the right type.
                // Attempt to cast Record to TRecord and check if the result is null.
                TRecord result = baseResult.As <TRecord>();
                if (result == null)
                {
                    // If cast result is null, the record was found but it is an instance
                    // of class that is not derived from TRecord, in this case the API
                    // requires error message, not returning null
                    throw new Exception(
                              $"Stored type {result.GetType().Name} for Key={key.Value} in " +
                              $"DataSet={loadFrom} is not an instance of the requested type {typeof(TRecord).Name}.");
                }

                // Initialize before returning
                result.Init(Context);
                return(result);
            }
            else
            {
                // Record not found or is a DeletedRecord, return null
                return(null);
            }
        }
        /// <summary>
        /// Load record from context.DataSource, overriding the dataset
        /// specified in the context with the value specified as the
        /// second parameter. The lookup occurs in the specified dataset
        /// and its imports, expanded to arbitrary depth with repetitions
        /// and cyclic references removed.
        ///
        /// IMPORTANT - this overload of the method loads from loadFrom
        /// dataset, not from context.DataSet.
        ///
        /// If Record property is set, its value is returned without
        /// performing lookup in the data store; otherwise the record
        /// is loaded from storage and cached in Record and the
        /// cached value is returned from subsequent calls.
        ///
        /// Once the record has been cached, the same version will be
        /// returned in subsequent calls with the same key instance.
        /// Create a new key or call earRecord() method to force
        /// reloading new version of the record from storage.
        ///
        /// Error message if the record is not found or is a DeletedRecord.
        /// </summary>
        public static TRecord Load <TKey, TRecord>(this DataSource obj, TypedKey <TKey, TRecord> key, TemporalId loadFrom)
            where TKey : TypedKey <TKey, TRecord>, new()
            where TRecord : TypedRecord <TKey, TRecord>
        {
            // This method will return null if the record is
            // not found or the found record is a DeletedRecord
            var result = obj.LoadOrNull(key, loadFrom);

            // Error message if null, otherwise return
            if (result == null)
            {
                throw new Exception(
                          $"Record with key {key} is not found in dataset with TemporalId={loadFrom}.");
            }

            return(result);
        }
 /// <summary>
 /// Write a DeletedRecord in deleteIn dataset for the specified key
 /// instead of actually deleting the record. This ensures that
 /// a record in another dataset does not become visible during
 /// lookup in a sequence of datasets.
 ///
 /// To avoid an additional roundtrip to the data store, the delete
 /// marker is written even when the record does not exist.
 /// </summary>
 public abstract void Delete <TKey, TRecord>(TypedKey <TKey, TRecord> key, TemporalId deleteIn)
     where TKey : TypedKey <TKey, TRecord>, new()
     where TRecord : TypedRecord <TKey, TRecord>;
 /// <summary>
 /// Load record by string key from the specified dataset or
 /// its list of imports. The lookup occurs first in descending
 /// order of dataset TemporalIds, and then in the descending
 /// order of record TemporalIds within the first dataset that
 /// has at least one record. Both dataset and record TemporalIds
 /// are ordered chronologically to one second resolution,
 /// and are unique within the database server or cluster.
 ///
 /// The root dataset has empty TemporalId value that is less
 /// than any other TemporalId value. Accordingly, the root
 /// dataset is the last one in the lookup order of datasets.
 ///
 /// The first record in this lookup order is returned, or null
 /// if no records are found or if DeletedRecord is the first
 /// record.
 ///
 /// Return null if there is no record for the specified TemporalId;
 /// however an exception will be thrown if the record exists but
 /// is not derived from TRecord.
 /// </summary>
 public abstract TRecord LoadOrNull <TKey, TRecord>(TypedKey <TKey, TRecord> key, TemporalId loadFrom)
     where TKey : TypedKey <TKey, TRecord>, new()
     where TRecord : TypedRecord <TKey, TRecord>;
 /// <summary>
 /// Write a DeletedRecord in deleteIn dataset for the specified key
 /// instead of actually deleting the record. This ensures that
 /// a record in another dataset does not become visible during
 /// lookup in a sequence of datasets.
 ///
 /// To avoid an additional roundtrip to the data store, the delete
 /// marker is written even when the record does not exist.
 /// </summary>
 public static void Delete <TKey, TRecord>(this Context obj, TypedKey <TKey, TRecord> key, TemporalId deleteIn)
     where TKey : TypedKey <TKey, TRecord>, new()
     where TRecord : TypedRecord <TKey, TRecord>
 {
     obj.DataSource.Delete(key, deleteIn);
 }
 /// <summary>
 /// Load record by string key from the specified dataset or
 /// its list of imports. The lookup occurs first in descending
 /// order of dataset TemporalIds, and then in the descending
 /// order of record TemporalIds within the first dataset that
 /// has at least one record. Both dataset and record TemporalIds
 /// are ordered chronologically to one second resolution,
 /// and are unique within the database server or cluster.
 ///
 /// The root dataset has empty TemporalId value that is less
 /// than any other TemporalId value. Accordingly, the root
 /// dataset is the last one in the lookup order of datasets.
 ///
 /// The first record in this lookup order is returned, or null
 /// if no records are found or if DeletedRecord is the first
 /// record.
 ///
 /// Return null if there is no record for the specified TemporalId;
 /// however an exception will be thrown if the record exists but
 /// is not derived from TRecord.
 /// </summary>
 public static TRecord LoadOrNull <TKey, TRecord>(this Context obj, TypedKey <TKey, TRecord> key, TemporalId loadFrom)
     where TKey : TypedKey <TKey, TRecord>, new()
     where TRecord : TypedRecord <TKey, TRecord>
 {
     return(obj.DataSource.LoadOrNull(key, loadFrom));
 }
 /// <summary>
 /// Load record from context.DataSource, overriding the dataset
 /// specified in the context with the value specified as the
 /// second parameter. The lookup occurs in the specified dataset
 /// and its imports, expanded to arbitrary depth with repetitions
 /// and cyclic references removed.
 ///
 /// This overload of the method loads from from context.DataSet.
 ///
 /// If Record property is set, its value is returned without
 /// performing lookup in the data store; otherwise the record
 /// is loaded from storage and cached in Record and the
 /// cached value is returned from subsequent calls.
 ///
 /// Once the record has been cached, the same version will be
 /// returned in subsequent calls with the same key instance.
 /// Create a new key or call earRecord() method to force
 /// reloading new version of the record from storage.
 ///
 /// Error message if the record is not found or is a DeletedRecord.
 /// </summary>
 public static TRecord Load <TKey, TRecord>(this Context obj, TypedKey <TKey, TRecord> key)
     where TKey : TypedKey <TKey, TRecord>, new()
     where TRecord : TypedRecord <TKey, TRecord>
 {
     return(obj.DataSource.Load(key, obj.DataSet));
 }
Beispiel #10
0
 /// <summary>
 /// Load record by string key from the specified dataset or
 /// its list of imports. The lookup occurs first in descending
 /// order of dataset TemporalIds, and then in the descending
 /// order of record TemporalIds within the first dataset that
 /// has at least one record. Both dataset and record TemporalIds
 /// are ordered chronologically to one second resolution,
 /// and are unique within the database server or cluster.
 ///
 /// The root dataset has empty TemporalId value that is less
 /// than any other TemporalId value. Accordingly, the root
 /// dataset is the last one in the lookup order of datasets.
 ///
 /// The first record in this lookup order is returned, or null
 /// if no records are found or if DeletedRecord is the first
 /// record.
 ///
 /// Return null if there is no record for the specified TemporalId;
 /// however an exception will be thrown if the record exists but
 /// is not derived from TRecord.
 /// </summary>
 public override TRecord LoadOrNull <TKey, TRecord>(TypedKey <TKey, TRecord> key, TemporalId loadFrom)
 {
     throw MethodCalledForNullDataSourceError();
 }
Beispiel #11
0
 /// <summary>
 /// Write a DeletedRecord in deleteIn dataset for the specified key
 /// instead of actually deleting the record. This ensures that
 /// a record in another dataset does not become visible during
 /// lookup in a sequence of datasets.
 ///
 /// To avoid an additional roundtrip to the data store, the delete
 /// marker is written even when the record does not exist.
 /// </summary>
 public override void Delete <TKey, TRecord>(TypedKey <TKey, TRecord> key, TemporalId deleteIn)
 {
     throw MethodCalledForNullDataSourceError();
 }