RavenDB OnBeforeStore does not fire using BulkInsert - ravendb

I cannot get OnBeforeStore to fire using a BulkInsert.
It fires fine during a regular Store operation.
I'm trying to use an Invoice number generator to add a formatted number and I'd like to do that in OnBeforeStore.
See code example:
static async Task GenerateInvoiceTest()
{
using var store = new DocumentStore
{
Urls = new string[] { "https://localhost:8080" },
Database = "APC",
};
//this never fires using BulkInsert
store.OnBeforeStore += (s, e) =>
{
if (!(e.Entity is Invoice invoice)) return;
if (invoice.InvoiceNumber != 0) return;
invoice.InvoiceNumber = new Random().Next(1, 1000);
};
store.Initialize();
//sample invoices
var invoices = new List<Invoice>
{
new Invoice { StartDate = DateTime.Now, EndDate = DateTime.Now.AddDays(3) },
new Invoice { StartDate = DateTime.Now, EndDate = DateTime.Now.AddDays(3) },
};
//bulk insert test
using var session = store.OpenAsyncSession();
using var bulkInsert = store.BulkInsert();
invoices.ForEach(i => bulkInsert.Store(i));
//this does NOT fire OnBeforeStore
await session.SaveChangesAsync();
foreach (var invoice in invoices)
{
//always prints 0
Console.WriteLine(invoice.InvoiceNumber);
}
//regular test
var otherInvoice = new Invoice { StartDate = DateTime.Now, EndDate = DateTime.Now.AddDays(3) };
await session.StoreAsync(otherInvoice);
//this DOES fire OnBeforeStore
await session.SaveChangesAsync();
}

OnBeforeStore is invoked as part of the Session SaveChanges method
See this documentation about OnBeforeStore
http://localhost:54391/docs/article-page/5.0/Csharp/client-api/session/how-to/subscribe-to-events
The event takes argument BeforeStoreEventArgs that consists of the Session entity's ID and the entity itself.
You define OnBeforeStore on the 'Store' but it is Not for use with bulkInsert.
It is for when saving from a Session.
BulkInsert operates on the Store itself, not on the Session

Related

Upload CSV data into SQL database using ASP.NET Core MVC

I am trying to insert data from a .csv file into my database, but anytime I upload data, the record is empty.
This is my code so far:
[HttpPost]
public async Task<IActionResult> ImportFromExcel(IFormFile formFile)
{
var data = new MemoryStream();
await formFile.CopyToAsync(data);
data.Position = 0;
TextReader reader = new StreamReader(data);
var csvReader = new CsvReader(reader, new CsvConfiguration(System.Globalization.CultureInfo.CurrentCulture)
{
HasHeaderRecord = true,
HeaderValidated = null,
MissingFieldFound = null
});
var Name = csvReader.GetField(0).ToString();
var dep = "cccccccccc";
var pos = "bbbbbbbbbbb";
await dcx.Participants.AddAsync(new Participant
{
Name = Name,
Position = pos,
Department = dep,
});
dcx.SaveChanges();
return ViewComponent("ViewParticipants");
}
This is the sample data in my database table:
As long as the headers of your CSV match up to the names of the columns in your database, you should be able to do something like this. If the names don't match, you can use .Name("CsvColumnName") in ParticipantMap to add the name of the column in the CSV file. Example: Map(r => r.Description).Name("MyCsvDescription");.
[HttpPost]
public async Task<IActionResult> ImportFromExcel(IFormFile formFile)
{
var data = new MemoryStream();
await formFile.CopyToAsync(data);
data.Position = 0;
var conf = new CsvConfiguration(CultureInfo.InvariantCulture)
{
HasHeaderRecord = true,
HeaderValidated = null,
MissingFieldFound = null,
BadDataFound = context =>
{
bad.Add(context.RawRecord);
}
};
using (TextReader reader = new StreamReader(data))
using (var csvReader = new CsvReader(reader, config)) {
csvReader.Context.RegisterClassMap<ParticipantMap>();
var records = csvReader.GetRecords<Participant>().ToList();
var dep = "cccccccccc";
var pos = "bbbbbbbbbbb";
records.ForEach(r =>
{
r.Department = dep;
r.Position = pos;
});
await dcx.Participants.AddRangeAsync(records);
dcx.SaveChanges();
}
return ViewComponent("ViewParticipants");
}
public class ParticipantMap : ClassMap<Participant>
{
public ParticipantMap()
{
AutoMap(CultureInfo.InvariantCulture);
Map(r => r.Department).Ignore();
Map(r => r.Position).Ignore();
}
}
In my opinion, you should call csvReader.Read() to read the file row first.
You can refer to the following test code, it works fine.
[HttpPost]
public async Task<IActionResult> ImportFromExcel(IFormFile formFile)
{
var data = new MemoryStream();
await formFile.CopyToAsync(data);
data.Position = 0;
using (var reader = new StreamReader(data))
{
var bad = new List<string>();
var conf = new CsvConfiguration(CultureInfo.InvariantCulture)
{
HasHeaderRecord = true,
HeaderValidated = null,
MissingFieldFound = null,
BadDataFound = context =>
{
bad.Add(context.RawRecord);
}
};
using (var csvReader = new CsvReader(reader, conf))
{
while (csvReader.Read())
{
var Name = csvReader.GetField(0).ToString();
var pos = csvReader.GetField(1).ToString();
var dep = csvReader.GetField(2).ToString();
await dcx.Participants.AddAsync(new Participant
{
Name = Name,
Position = pos,
Department = dep,
});
dcx.SaveChanges();
}
}
}
return ViewComponent("ViewParticipants");
}
Test Result:

How to update AppDBContext in ASP.NET Core Web API

I am quite new to ASP.NET and I am bit stuck with this.
I am creating an entry in my DB while registering the user:
private async Task<bool> CreateEntryInUserActions(AppUser user)
{
var entity = new UserActionEntity
{
UserId = user.Id,
};
await _context.tbl_UserActions.AddAsync(entity);
await _context.SaveChangesAsync();
return true;
}
I want to change the IsPasswordChanged field in the UserActions table to true when a user changes his/her password.
I am trying something like:
private async Task<bool> UpdateUserAction()
{
var userId = _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value; // gives me current user's id
var user = _context.tbl_UserActions
.Where(x => x.UserId.ToString() == userId).Select(x => x.IsPasswordChanged);
}
but I am not sure how to proceed and update this to "true". How do I update this entry?
You need to fetch the useraction entity from the table and then set the IsPasswordChanged property to true.
Try this:
private async Task<bool> UpdateUserAction()
{
var userId = _httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value; // gives me current user's id
var user = _context.tbl_UserActions.FirstOrDefault(x => x.UserId.ToString() == userId);
if(user != null) //check if the record is not null
{
user.IsPasswordChanged = true; // set the column to desired value
_context.tbl_UserActions.Update(user);
await _context.SaveChangesAsync();
}
}

c# Copy SQL table data to another DB with Where clause filter using Data Factory

I am in a process to copy data from one SQL database (Source) and move to another SQL Database (destination) through data factory using c# code.
I am able to copy all the data from a source table to destination table, but i want to move filtered data only, like SELECT * FROM Source.tbl WHERE Category = 5. There would be around 10-15 table that i would move data. Can you provide me sample code which may help me?
My code for moving single table all data..
// Authenticate and create a data factory management client
var context = new AuthenticationContext("https://login.windows.net/" + tenantID);
ClientCredential cc = new ClientCredential(AppID, AuthKey);
AuthenticationResult result = context.AcquireTokenAsync("https://management.azure.com/", cc).Result;
ServiceClientCredentials cred = new TokenCredentials(result.AccessToken);
var client = new DataFactoryManagementClient(cred) { SubscriptionId = SubscriptionID };
// Create data factory
Factory dataFactory = new Factory { Location = Region, Identity = new FactoryIdentity() };
// This line throws error, we cannot proceed further. unless we get access of creating DF or update or access.
client.Factories.CreateOrUpdate(ResourceGroup, DataFactoryName, dataFactory);
var DF = client.Factories.Get(ResourceGroup, DataFactoryName);
while (DF.ProvisioningState == "PendingCreation")
{
System.Threading.Thread.Sleep(1000);
}
LinkedServiceResource storageLinkedService = new LinkedServiceResource(
new AzureSqlDatabaseLinkedService
{
ConnectionString = new SecureString(SourceSQLConnString)
}
);
client.LinkedServices.CreateOrUpdate(ResourceGroup, DataFactoryName, SourceSQLLinkedServiceName, storageLinkedService);
LinkedServiceResource sqlDbLinkedService = new LinkedServiceResource(
new AzureSqlDatabaseLinkedService
{
ConnectionString = new SecureString(DestSQLConnString)
}
);
client.LinkedServices.CreateOrUpdate(ResourceGroup, DataFactoryName, DestSQLLinkedServiceName, sqlDbLinkedService);
DatasetResource SourceSQLDataSet = new DatasetResource(
new AzureSqlTableDataset
{
LinkedServiceName = new LinkedServiceReference
{
ReferenceName = SourceSQLLinkedServiceName
},
TableName = Table,
}
);
client.Datasets.CreateOrUpdate(ResourceGroup, DataFactoryName, SourceSQLDataSetName, SourceSQLDataSet);
// Create a Azure SQL Database dataset
DatasetResource DestSQLDataSet = new DatasetResource(
new AzureSqlTableDataset
{
LinkedServiceName = new LinkedServiceReference
{
ReferenceName = DestSQLLinkedServiceName
},
TableName = Table
}
);
client.Datasets.CreateOrUpdate(ResourceGroup, DataFactoryName, DestSQLDataSetName, DestSQLDataSet);
PipelineResource pipeline = new PipelineResource
{
Activities = new List<Activity>
{
new CopyActivity
{
Name = "CopyFromSQLToSQL",
Inputs = new List<DatasetReference>
{
new DatasetReference()
{
ReferenceName = SourceSQLDataSetName
}
},
Outputs = new List<DatasetReference>
{
new DatasetReference
{
ReferenceName = DestSQLDataSetName
}
},
Source = new SqlSource(),
Sink = new SqlSink { }
}
}
};
client.Pipelines.CreateOrUpdate(ResourceGroup, DataFactoryName, PipelineName, pipeline);
// Create a pipeline run
CreateRunResponse runResponse = client.Pipelines.CreateRunWithHttpMessagesAsync(ResourceGroup, DataFactoryName, PipelineName).Result.Body;
// Monitor the pipeline run
PipelineRun pipelineRun;
while (true)
{
pipelineRun = client.PipelineRuns.Get(ResourceGroup, DataFactoryName, runResponse.RunId);
if (pipelineRun.Status == "InProgress")
System.Threading.Thread.Sleep(15000);
else
break;
}
You could put your query into the SqlReaderQuery property of your sql Source.
I talked to the Data Factory support, they said we have not implemented yet,
Create Data Factory,
Create linked services
In loop create datasets and Create copy activity

How to use Scroll while passing raw json Query to ElasticSearch using NEST

var query = #"
{
""query"": {
""match_all"": { }
}
}";
Func<SearchRequestParameters, SearchRequestParameters> requestParameters = a =>
a.SearchType(SearchType.Scan).Scroll(TimeSpan.FromSeconds(60));
var searchResult = await client.LowLevel.SearchAsync<SearchResponse<T>>(indexName, mappingName, query , requestParameters)
if (searchResult.Body.IsValid)
{
var scrollNo = 0;
var results = await client.ScrollAsync<T>("10s", searchResult.Body.ScrollId);
while (results.Documents.Any())
{
documents.AddRange(results.Documents);
scrollNo++;
results = await client.ScrollAsync<T>("10s", results.ScrollId);
return new Customresponse<T>
{
Documents = documents,
total = result.Body.Total
};
}
Would like to pull all data using scroll while passing raw json query. but scroll is not working properly while passing json raw query. Can anyone help on this ?.
Your example is nearly there but not quite; you're missing a closing brace for the while loop to collect all documents before returning the custom response.
Here's an example I just ran on the Stackoverflow data set, to return all questions tagged with nest
private IElasticClient _client;
void Main()
{
var pool = new SingleNodeConnectionPool(new Uri("http://localhost:9200"));
var defaultIndex = "default-index";
var connectionSettings = new ConnectionSettings(pool);
_client = new ElasticClient(connectionSettings);
var query = #"
{
""query"": {
""term"": {
""tags"": {
""value"": ""nest""
}
}
}
}";
var result = RunScrollAsync(query).Result.Dump();
}
private async Task<Customresponse<Question>> RunScrollAsync(string query)
{
var scrollTime = "10s";
// omit the .SearchType(Scan) which is deprecated. Not
// specifying means the first response contains the first set
// of documents
var esResponse = await _client.LowLevel.SearchAsync<SearchResponse<Question>>(
"posts",
"question",
query, r => r.Scroll(TimeSpan.FromSeconds(10))).ConfigureAwait(false);
if (esResponse.Body.IsValid && esResponse.Body.Documents.Any())
{
// assume you have less than 2,147,483,647 documents to return?
var documents = new List<Question>((int)esResponse.Body.Total);
documents.AddRange(esResponse.Body.Documents);
var scrollNo = 0;
var response = await _client.ScrollAsync<Question>(scrollTime, esResponse.Body.ScrollId).ConfigureAwait(false);;
// keep scrolling until no more documents are returned
while (response.Documents.Any())
{
documents.AddRange(response.Documents);
scrollNo++;
response = await _client.ScrollAsync<Question>(scrollTime, response.ScrollId).ConfigureAwait(false);;
}
return new Customresponse<Question>
{
Documents = documents,
total = response.Total
};
}
// return an empty result.
// Or throw an exception, or log - whatever you need to do
return new Customresponse<Question>
{
Documents = Enumerable.Empty<Question>(),
total = 0
};
}
public class Customresponse<T>
{
public IEnumerable<T> Documents { get; set; }
public long total { get; set; }
}
This returns all 342 questions, with a total of 342 (Data set is from June 2016).

How to programmatically set the task outcome (task response) of a Nintex Flexi Task?

Is there any way of set a Nintex Flexi task completion through Sharepoint's web services? We have tried updating the "WorkflowOutcome", "ApproverComments" and "Status" fields without success (actually the comments and status are successfully updated, however I can find no way of updating the WorkflowOutcome system field).
I can't use the Nintex Web service (ProcessTaskResponse) because it needs the task's assigned user's credentials (login, password, domain).
The Asp.net page doesn't have that information, it has only the Sharepoint Administrator credentials.
One way is to delegate the task to the admin first, and then call ProcessTaskResponse, but it isn't efficient and is prone to errors.
In my tests so far, any update (UpdateListItems) to the WorkflowOutcome field automatically set the Status field to "Completed" and the PercentComplete field to "1" (100%), ending the task (and continuing the flow), but with the wrong answer: always "Reject", no matter what I try to set it to.
Did you try this code: (try-cacth block with redirection does the trick)
\\set to actual outcome id here, for ex. from OutComePanel control
taskItem[Nintex.Workflow.Common.NWSharePointObjects.FieldDecision] = 0;
taskItem[Nintex.Workflow.Common.NWSharePointObjects.FieldComments] = " Some Comments";
taskItem.Update();
try
{
Nintex.Workflow.Utility.RedirectOrCloseDialog(HttpContext.Current, Web.Url);
}
catch
{
}
?
Here are my code to change outcome of nintex flexi task. My problem is permission. I had passed admin token to site. It's solve the problem.
var siteUrl = "...";
using (var tempSite = new SPSite(siteUrl))
{
var sysToken = tempSite.SystemAccount.UserToken;
using (var site = new SPSite(siteUrl, sysToken))
{
var web = site.OpenWeb();
...
var cancelled = "Cancelled";
task.Web.AllowUnsafeUpdates = true;
Hashtable ht = new Hashtable();
ht[SPBuiltInFieldId.TaskStatus] = SPResource.GetString(new CultureInfo((int)task.Web.Language, false), Strings.WorkflowStatusCompleted, new object[0]);
ht["Completed"] = true;
ht["PercentComplete"] = 1;
ht["Status"] = "Completed";
ht["WorkflowOutcome"] = cancelled;
ht["Decision"] = CommonHelper.GetFlexiTaskOutcomeId(task, cancelled);
ht["ApproverComments"] = "cancelled";
CommonHelper.AlterTask((task as SPListItem), ht, true, 5, 100);
task.Web.AllowUnsafeUpdates = false;
}
}
}
}
}
}
public static string GetFlexiTaskOutcomeId(Microsoft.SharePoint.Workflow.SPWorkflowTask task, string outcome)
{
if (task["MultiOutcomeTaskInfo"] == null)
{
return string.Empty;
}
string xmlOutcome = HttpUtility.HtmlDecode(task["MultiOutcomeTaskInfo"].ToString());
if (string.IsNullOrEmpty(xmlOutcome))
{
return string.Empty;
}
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlOutcome);
var node = doc.SelectSingleNode(string.Format("/MultiOutcomeResponseInfo/AvailableOutcomes/ConfiguredOutcome[#Name='{0}']", outcome));
return node.Attributes["Id"].Value;
}
public static bool AlterTask(SPListItem task, Hashtable htData, bool fSynchronous, int attempts, int milisecondsTimeout)
{
if ((int)task[SPBuiltInFieldId.WorkflowVersion] != 1)
{
SPList parentList = task.ParentList.ParentWeb.Lists[new Guid(task[SPBuiltInFieldId.WorkflowListId].ToString())];
SPListItem parentItem = parentList.Items.GetItemById((int)task[SPBuiltInFieldId.WorkflowItemId]);
for (int i = 0; i < attempts; i++)
{
SPWorkflow workflow = parentItem.Workflows[new Guid(task[SPBuiltInFieldId.WorkflowInstanceID].ToString())];
if (!workflow.IsLocked)
{
task[SPBuiltInFieldId.WorkflowVersion] = 1;
task.SystemUpdate();
break;
}
if (i != attempts - 1)
{
Thread.Sleep(milisecondsTimeout);
}
}
}
var result = SPWorkflowTask.AlterTask(task, htData, fSynchronous);
return result;
}