/// <summary> /// Static method that asyncronously fetches data from the API and writes the next id to a file. /// </summary> public static async void ApiFetch(IServiceProvider serviceProvider) { InitializeDictionaries(); // Let our web service start before we start fetching data. await Task.Delay(initialDelay); ReadNextIdFromFile(); SetNextAddress(); while (fetching) { // Print the current ID for debugging and testing. Console.WriteLine("Started parsing API with id " + nextId); try { string stringJsonContent = await httpClient.GetStringAsync(nextAddress); JObject jsonContent = JObject.Parse(stringJsonContent); JArray jsonStashes = (JArray)jsonContent.SelectToken("stashes"); using (var context = new StashContext(serviceProvider .GetRequiredService <DbContextOptions <StashContext> >())) { context.StoreMaps(jsonStashes); } nextId = (string)jsonContent.SelectToken("next_change_id"); WriteNextIdToFile(); SetNextAddress(); } catch (Exception e) { // If we somehow made too many requests, make sure to not continue it. // Future TODO: site maintenance and other responses. string errMsg = e.Message; switch (errMsg) { case "Response status code does not indicate success: 429 (Too Many Requests).": await Task.Delay(floodDelay); break; default: break; } Console.WriteLine(e.Message); } // Wait a bit before making another request to avoid flooding / errors. await Task.Delay(timeDelay); } }
ContextInsertOrMerge <T>( StashContext <T> context, int count, string partitionKey) where T : IDataHelper <T>, new() { return(ContextPlace <T>(context, count, partitionKey, context.InsertOrMerge)); }
ContextQuery <T>( string partitionKey, StashContext <T> context, IQueryable <T> query, CommitStrategy commitStrategy) where T : IDataHelper <T>, new() { // Insert const int insertCount = 5; var insertItems = ContextInsert <T>(context, insertCount, partitionKey); Assert.IsTrue(context.GetTrackedEntities(EntityState.Inserted).Count == insertCount); context.Commit(commitStrategy); Assert.IsTrue(context.GetTrackedEntities(EntityState.Unchanged).Count == insertCount); // Detach a few var detachedItems = insertItems.Where((item, idx) => idx % 2 == 1).ToList(); int detachCount = detachedItems.Count; detachedItems.ForEach(item => context.Detach(item)); Assert.IsTrue(context.GetTrackedEntities(EntityState.Unchanged).Count == insertCount - detachCount); // query var queryItems = query.ToList(); Assert.IsTrue(queryItems.Count == insertCount); Assert.IsTrue(context.GetTrackedEntities(EntityState.Unchanged).Count == insertCount); // delete queryItems.ForEach(context.Delete); context.Commit(commitStrategy); Assert.IsTrue( context.GetTrackedEntities().Count == 0); }
ContextPlace <T>( StashContext <T> context, int count, string partitionKey, Action <T> action) where T : IDataHelper <T>, new() { return(Enumerable .Range(1, count) .Select( i => { var item = TypeFactory <T> .CreateRandomSmall(); item.SetPartitionKey(partitionKey); action(item); return item; }).ToList()); }
Tutorial_08_Context() { //---------------------------------------------------------------------------------------------------------- // Create Stash Client and get a new context StashClient <Employee> client = StashConfiguration.GetClient <Employee>(); client.CreateTableIfNotExist(); StashContext <Employee> context = client.GetContext(); //---------------------------------------------------------------------------------------------------------- // Create instances of the class, place in the context and commit the changes. const int insertCount = 10; string departmentDev = Guid.NewGuid().ToString(); // create n employees and insert into the context Enumerable .Range(1, insertCount) .Select( idx => { Employee employee = new Employee { Department = departmentDev, EmployeeId = Guid.NewGuid().ToString(), Name = "John Doe", SkillLevel = 8, DateOfBirth = new DateTime(1990 - idx, 1, 1) }; // update the private field employee.SetAnnualSalary(); return(employee); }) .ToList() .ForEach( item => context.Insert(item)); // validate the the context now contains n items with the correct state. int contextInsertCount = context .GetTrackedEntities(EntityState.Inserted) .Count; Assert.IsTrue(contextInsertCount == insertCount); // commit the context // CommitStrategy.Serial, commits each insert as a single request // This is the default strategy and need not be passed in - context.Commit() would work the same context.Commit(CommitStrategy.Serial); // On a successful commit, the state of the entity changes to EntityState.Unchanged. // validate that the context contains n items with the correct state int contextUnchangedState = context .GetTrackedEntities(EntityState.Unchanged) .Count; Assert.IsTrue(contextInsertCount == contextUnchangedState); //---------------------------------------------------------------------------------------------------------- // The context continues to hold on to the entities so it is often a good idea to either clear the context // if the entities are no longer needed or better still to just create a new context. //---------------------------------------------------------------------------------------------------------- // Get a new context and query for the rows we inserted earlier by using the same partition key, // departmentDev context = client.GetContext(); context.CreateQuery().Where(emp => emp.Department == departmentDev).ToList(); // Confirm we have the corrent number of items in the context Assert.IsTrue(context.GetTrackedEntities().Count == insertCount); // Make changes to this collection of employees in the context, modifying some and deleting the others. int entityIdx = 0; int updateCount = 0; int deleteCount = 0; context .GetTrackedEntities() .ForEach( entityDescriptor => { Employee employee = entityDescriptor.Entity; if (entityIdx % 3 == 0) { context.Delete(employee); // delete every 3rd one ++deleteCount; } else // update the others { ++employee.SkillLevel; employee.SetAnnualSalary(); // change the salary of of the employee context.Update(employee); // and update in the context ++updateCount; } ++entityIdx; }); // Commit the context, this time use the Parallel strategy. // The Parallel strategy will perform all requests in parallel. In the event of an error, // a single aggregate StashAggregateException is returned containing one or more of the errors. context.Commit(CommitStrategy.Parallel); // Performing a delete will remove an entity form the context. Validate this. Assert.IsTrue(context.GetTrackedEntities().Count == insertCount - deleteCount); //---------------------------------------------------------------------------------------------------------- // Now delete all the other entities in the context context.GetTrackedEntities().ForEach( entityDescriptor => context.Delete(entityDescriptor.Entity)); // Commit the context, this time use the batch strategy. // In a nutshell, Batch is a mode supported by Azure table storage which allows, // a number and size limited request to be made. // Batch is only allowed on entities within the same Partition and has an all or none success guarantee. context.Commit(CommitStrategy.Batch); // If all were deleted successfully the context should not be tracking any entities. Assert.IsTrue(context.GetTrackedEntities().Count == 0); //---------------------------------------------------------------------------------------------------------- // So far so good. This concludes this part of the tutorial. Go Stash! }
public IndexModel(StashContext context) { Context = context; }