/// <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)); }
/// <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(); }
/// <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(); }