update table in Azure Mobile Service - azure

How to update particular record in azure mobile Service. For Example I have a table in azure called country having two columns
country_id
country_name
If I want to update the record with country_id=5 from USA to United State of America. How to Perform this.
//Global Variable
private MobileServiceCollection<country, country> items;
private IMobileServiceTable<country> todoTable = App.MobileService.GetTable<country>();
class country
{
public string id { get; set; }
public string country_name { get; set; }
public int country_id { get; set; }
}
private async void btnUpdate_Click(object sender, RoutedEventArgs e)
{
var change = await todoTable
.Where(todoItem => todoItem.country_name == tboxcName.Text)
.ToListAsync();
await todoTable.UpdateAsync(change);
}
The above code I tried from this post, but did not find out.

You might want to try this:
private async void btnUpdate_Click(object sender, RoutedEventArgs e)
{
var change = await todoTable
.Where(todoItem => todoItem.id.Equals(tboxcName.Text))
.ToListAsync();
if(change != null){
var toChange= change.First();
toChange.country_name="United State of America";
await todoTable.UpdateAsync(toChange);
}
else{
// you have nothing to change, you might throw an exception
}
}
In the textbox you should enter the id you want to update, in your case it's 5. Then I make a linq query selecting all the items with Id "5", this gets me a list.
I check if the list is not void, you would want to threat the case when the list is null. If it's not null I take the first element (as you are in the mobile services the id field is unique in the database, so you don't have to threat this boundary case (although if you really want to be sure it's always better to do it)).
The first element in the list will have the ID=5, so we change the object updating it's country name to "United States of America" (in your case, you don't care of the previous value, as you are updating a specific ID). Then you update this item. The mobile service API will then issue a patch request, and the database will patch it according to the Object ID.
Hope this helps!

Try with this C# code!
private async void btnUpdate_Click(object sender, RoutedEventArgs e)
{
var filteredRecords = await todoTable.Where(
todoItem => todoItem.country_id == 5)
.ToListAsync();
foreach (var item in filteredRecords)
{
item.country_name="United States of America";
await todoTable.UpdateAsync(item);
}
}

Related

Copy User Fields from CRM Quote to Sales Order

I am trying to copy some user fields from the CRM Quote to the Sales Order. The CRM Quote uses a different object than the Sales Quote and there doesn't appear to be a way to relate it back. I tried overriding the Create Sales Order to add a handler, but this didn't seem to work Any help would be appreciated. Here is the code I tried:
public class OpportunityMaint_Extension : PXGraphExtension<OpportunityMaint>
{
public delegate IEnumerable CreateSalesOrderDelegate(PXAdapter adapter);
[PXOverride]
public virtual IEnumerable CreateSalesOrder(PXAdapter adapter, CreateSalesOrderDelegate baseMethod)
{
Base.RowInserting.AddHandler<SOLine>((sender, e) =>
{
SOLine orderLine = e.Row as SOLine;
if (orderLine == null) return;
SOLineExt orderLineExt = orderLine.GetExtension<SOLineExt>();
var product = Base.Products.Current;
CROpportunityProductsExt productExt = product.GetExtension<CROpportunityProductsExt>();
orderLineExt.UsrHasAnticipatedDiscount = productExt.UsrHasAnticipatedDiscount;
orderLineExt.UsrAnticipatedDiscountPct = productExt.UsrAnticipatedDiscountPct;
orderLineExt.UsrAnticipatedDiscountAmt = productExt.UsrAnticipatedDiscountAmt;
orderLineExt.UsrAnticipatedUnitPrice = productExt.UsrAnticipatedUnitPrice;
orderLineExt.UsrTotalAnticipatedDiscountAmt = productExt.UsrTotalAnticipatedDiscountAmt;
});
return baseMethod(adapter);
}
}
Thanks!
There are two posts with answers to this same question:
Populate custom field while creating sale order from opportunity
How to pass custom field vales from Opportunity to sales Order?
To sum it up, you can add a rowinserting event handler within the button action or my preference is within DoCreateSalesOrder (extending OpportunityMaint) like the example below...
[PXOverride]
public virtual void DoCreateSalesOrder(OpportunityMaint.CreateSalesOrderFilter param, Action<OpportunityMaint.CreateSalesOrderFilter> del)
{
PXGraph.InstanceCreated.AddHandler<SOOrderEntry>(graph =>
{
graph.RowInserting.AddHandler<SOLine>((cache, args) =>
{
var soLine = (SOLine)args.Row;
if (soLine == null)
{
return;
}
CROpportunityProducts opProduct = PXResult<CROpportunityProducts>.Current;
if (opProduct == null)
{
return;
}
var opProductExt = PXCache<CROpportunityProducts>.GetExtension<CROpportunityProductsExt>(opProduct);
var soLineExt = PXCache<SOLine>.GetExtension<SOLineExt>(soLine);
//Copy all extension fields here...
});
});
del(param);
}

How to deal with Context.Done(R value)

I have a msbot chat dialog that I want to have the following behaviour:
user -> get me some info about GARY
bot -> which gary, (prompt: choice options)
user -> gary peskett
bot -> sure, (hero card with gary's contact details)
I have this code
public class CustomerRepository
{
private IList<Customer> _customerList = new List<Customer>
{
new Customer
{
Name = "Gary Peskett"
},
new Customer
{
Name = "Gary Richards"
},
new Customer
{
Name = "Barry White"
}
};
public async Task<IEnumerable<Customer>> GetAll()
{
// usually calls a database (which is why async is on this method)
return _customerList;
}
}
public class XDialog : IDialog
{
private readonly IIntent _intent;
private readonly CustomerRepository _customerRepository;
public XDialog(IIntent intent, CustomerRepository customerRepository)
{
// An intent is decided before this point
_intent = intent;
_customerRepository = customerRepository;
}
public async Task StartAsync(IDialogContext context)
{
// // An intent can provide parameters
string name = _intent.Parameters["Name"] as string;
IEnumerable<Customer> customers = await _customerRepository.GetAll();
IList<Customer> limitedList = customers.Where(x => x.Name.Contains(name)).ToList();
if (limitedList.Any())
{
if (limitedList.Count > 1)
{
PromptDialog.Choice(context, LimitListAgain, limitedList,
"Can you specify which customer you wanted?");
}
else
{
Customer customer = limitedList.FirstOrDefault();
Finish(context, customer);
}
}
else
{
context.Done("No customers have been found");
}
}
private static async Task LimitListAgain(IDialogContext context, IAwaitable<Customer> result)
{
Customer customer = await result;
Finish(context, customer);
}
private static void Finish(IDialogContext context, Customer customer)
{
HeroCard heroCard = new HeroCard
{
Title = customer?.Name
};
context.Done(heroCard);
}
}
What i'm finding is that usually when I do context.Done(STRING) then that is output to the user, and this is really useful to end the dialog. As I want to end with a hero card, its outputing the typename
Microsoft.Bot.Connector.HeroCard
Can anyone help by either explaining a better way to use context.Done(R value) or help me return a hero card to end the dialog?
The dialog is being called with
Chain.PostToChain()
.Select(msg => Task.Run(() => _intentionService.Get(msg.ChannelId, msg.From.Id, msg.Text)).Result)
.Select(intent => _actionDialogFactory.Create(intent)) // returns IDialog based on intent
.Unwrap()
.PostToUser();
I think the problem is a side effect of using Chain.
As you may know, the context.Done doesn't post anything back to the user, it just ends the current dialog with the value provided.
The post to user is effectively happening in the .PostToUser() at the end of your Chain. Now, by looking into the PostToUser's code, I realized that at the end of the game, it's doing a context.PostAsync of item.ToString(), being item the payload provided in the context.Done in this case. See this.
One option (I haven't tested this), could be using .Do instead of .PostToUser() and manually perform what the PostToUserDialog does and finally perform a context.PostAsync() by creating a new IMessageActivity and adding the HeroCard as an attachment.

How to insert multiple objects in to Azure Mobile Services table controller [.Net backend]

I have an Azure Mobile service coded in .net Web API. I have a TableController. I want that table controller to be able to insert multiple persons, not just one person with from the client with InsertAsync(myPerson). I have the following code in the TableController:
[RequiresAuthorization(AuthorizationLevel.Admin)]
public async Task<bool> InsertPersons(List<Person> values)
{
try
{
foreach (var item in values)
{
var current = await InsertAsync(item);
}
return true;
}
catch (System.Exception)
{
return false;
}
}
The problem is in the client. Because it is strongly typed it only allows me to insert one item at a time. How must I call the server from the client? Do I have to write a Custom Api Controller and call it with mobileService.InvokeApiAsync? If so, how can I get access to my database from a Custom API Controller that doesn't inherit from TableController?
Thank you so much!
The helper methods in the TableController<T> base class assume that the insert operations apply to a single object - and the InsertAsync method in the client also assumes the same. So even though you can define in a table controller a method that takes an array (or list) of Person, you won't be able to call it via the client SDK (at least not without some heavy-lifting using a handler, for example).
You can, however, create a custom API which takes such a list. And to insert the multiple items from the API, you can access the context directly, without needing to go through the helper methods from the table:
public class PersonController : ApiController
{
test20140807Context context;
protected override void Initialize(HttpControllerContext controllerContext)
{
base.Initialize(controllerContext);
this.context = new test20140807Context();
}
[HttpPost]
public async Task<bool> InsertPersons(List<Person> values)
{
foreach (var value in values)
{
if (string.IsNullOrEmpty(value.Id))
{
value.Id = Guid.NewGuid().ToString();
}
}
try
{
this.context.People.AddRange(values);
await this.context.SaveChangesAsync();
return true;
}
catch (System.Exception ex)
{
Trace.WriteLine("Error: " + ex);
return false;
}
}
}
And on the client:
private async void btnTest_Click(object sender, RoutedEventArgs e)
{
var items = new Person[]
{
new Person { Name = "John Doe", Age = 33 },
new Person { Name = "Jane Roe", Age = 32 }
};
try
{
var response = await App.MobileService.InvokeApiAsync<Person[], bool>("person", items);
Debug.WriteLine("response: " + response);
}
catch (Exception ex)
{
var str = ex.ToString();
Debug.WriteLine(str);
}
}
From Carlos Figueira's post on inserting multiple items at once in azure mobile services, it looks like what you need to do is create another table called AllPersons. In your client, the AllPersons object would have a Persons array member. In your server side script for the AllPersons insert, you iterate through the AllPersons.Persons and insert into the table one by one.

CRM 2011: Custom Workflow Activity Output Parameters don´t show

everyone,
I'm having a problem that does not appear in the output parameter list on the right side under "Look for" underneath "Local Values", I do not understand the problem or reason for not appear, since in terms of input parameters's okay.
protected override void Execute(CodeActivityContext executionContext)
{
ITracingService tracingService = executionContext.GetExtension<ITracingService>();
//Create the context
IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();
IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
tracingService.Trace("Creating Account");
Account entity = new Account();
entity.Name = AccountName.Get<string>(executionContext);
Guid entityId = service.Create(entity);
string a = entity.Name;
AccountNameTest.Set(executionContext, a);
tracingService.Trace("Account created with Id {0}", entityId.ToString());
tracingService.Trace("Create a task for the account");
Task newTask = new Task();
newTask.Subject = TaskSubject.Get<string>(executionContext);
newTask.RegardingObjectId = new EntityReference(Account.EntityLogicalName, entityId);
Guid taskId = service.Create(newTask);
tracingService.Trace("Task has been created");
tracingService.Trace("Retrieve the task using QueryByAttribute");
QueryByAttribute query = new QueryByAttribute();
query.Attributes.AddRange(new string[] { "regardingobjectid" });
query.ColumnSet = new ColumnSet(new string[] { "subject" });
query.EntityName = Task.EntityLogicalName;
query.Values.AddRange(new object[] { entityId });
tracingService.Trace("Executing the Query for entity {0}", query.EntityName);
//Execute using a request to test the OOB (XRM) message contracts
RetrieveMultipleRequest request = new RetrieveMultipleRequest();
request.Query = query;
Collection<Entity> entityList = ((RetrieveMultipleResponse)service.Execute(request)).EntityCollection.Entities;
//Execute a request from the CRM message assembly
tracingService.Trace("Executing a WhoAmIRequest");
service.Execute(new WhoAmIRequest());
if (1 != entityList.Count)
{
tracingService.Trace("The entity list was too long");
throw new InvalidPluginExecutionException("Query did not execute correctly");
}
else
{
tracingService.Trace("Casting the Task from RetrieveMultiple to strong type");
Task retrievedTask = (Task)entityList[0];
if (retrievedTask.ActivityId != taskId)
{
throw new InvalidPluginExecutionException("Incorrect task was retrieved");
}
tracingService.Trace("Retrieving the entity from IOrganizationService");
//Retrieve the task using Retrieve
retrievedTask = (Task)service.Retrieve(Task.EntityLogicalName, retrievedTask.Id, new ColumnSet("subject"));
if (!string.Equals(newTask.Subject, retrievedTask.Subject, StringComparison.Ordinal))
{
throw new InvalidPluginExecutionException("Task's subject did not get retrieved correctly");
}
//Update the task
retrievedTask.Subject = UpdatedTaskSubject.Get<string>(executionContext);
service.Update(retrievedTask);
}
}
//
[Input("Name conta")]
[Default("testv01")]
public InArgument<string> AccountName { get; set; }
[Input("Task")]
[Default("testv01")]
public InArgument<string> TaskSubject { get; set; }
[Input("Update task")]
[Default("testUPDATED:v01}")]
public InArgument<string> UpdatedTaskSubject { get; set; }
[Output("Account ID Guid")]
[Default("testUPDATED:v01")]
public OutArgument<string> AccountNameTest { get; set; }
Ok, problem solved, just restart IIS to assume the fields, or through version change. The problem was the update of the plugin, this also happens with workflows. According to CRM 4.0 i realized this situation does not happen in CRM 4.0.
Even though this Question is already answered I wanted to share two Cases where this solution didn't work (even in a recent Version of CRM):
Case 1
Having choosen Input-Parameter-Names that contained german Umlauts (äöüß).
IIS-restart did not help.
Choosing Names without Umlauts solved the Problem for me.
Case 2
We recently also had a case where a normal In-Argument did not show up, even after restarting the entire Maschine CRM was running on. The Solution was not to obvious:
Open PluginRegistrationTool from SDK
Choose the Assembly that contains your CWA
Choose your CWA
Hit the Save-Button in the Properties-Tab of your CWA

Retrieving values of ReadOnly fields from DynamicData DetailsView in Edit Mode on Updating using LinqDataSource

I have several tables in my database that have read-only fields that get set on Inserting and Updating, namely: AddDate (DateTime), AddUserName (string), LastModDate (DateTime), LastModUserName (string).
All of the tables that have these values have been set to inherit from the following interface:
public interface IUserTrackTable
{
string AddUserName { get; set; }
DateTime AddDate { get; set; }
string LastModUserName { get; set; }
DateTime LastModDate { get; set; }
}
As such, I have the following method on the Edit.aspx page:
protected void DetailsDataSource_Updating(object sender, LinqDataSourceUpdateEventArgs e)
{
IUserTrackTable newObject = e.NewObject as IUserTrackTable;
if (newObject != null)
{
newObject.LastModUserName = User.Identity.Name;
newObject.LastModDate = DateTime.Now;
}
}
However, by the time it hits this method, the e.OriginalObject has already lost the values for all four fields, so a ChangeConflictException gets thrown during the actual Update. I have tried adding the four column names to the DetailsView1.DataKeyNames array in the Init event handler:
protected void Page_Init(object sender, EventArgs e)
{
// other things happen before this
var readOnlyColumns = table.Columns.Where(c => c.Attributes.SingleOrDefaultOfType<ReadOnlyAttribute>(ReadOnlyAttribute.Default).IsReadOnly).Select(c => c.Name);
DetailsView1.DataKeyNames = DetailsView1.DataKeyNames.Union<string>(readOnlyColumns).ToArray<string>();
DetailsView1.RowsGenerator = new CustomFieldGenerator(table, PageTemplates.Edit, false);
// other things happen after this
}
I've tried making that code only happen on PostBack, and still nothing. I'm at a lose for how to get the values for all of the columns to make the round-trip.
The only thing the CustomFieldGenerator is handling the ReadOnlyAttribute, following the details on C# Bits.
UPDATE: After further investigation, the values make the round trip to the DetailsView_ItemUpdating event. All of the values are present in the e.OldValues dictionary. However, they are lost by the time it gets to the LinqDataSource_Updating event.
Obviously, there are the "solutions" of making those columns not participate in Concurrency Checks or other ways that involve hard-coding, but the ideal solution would dynamically add the appropriate information where needed so that this stays as a Dynamic solution.
i Drovani, I assume you want data auditing (see Steve Sheldon's A Method to Handle Audit Fields in LINQ to SQL), I would do this in the model in EF4 you can do it like this:
partial void OnContextCreated()
{
// Register the handler for the SavingChanges event.
this.SavingChanges += new EventHandler(context_SavingChanges);
}
private static void context_SavingChanges(object sender, EventArgs e)
{
// handle auditing
AuditingHelperUtility.ProcessAuditFields(objects.GetObjectStateEntries(EntityState.Added));
AuditingHelperUtility.ProcessAuditFields(objects.GetObjectStateEntries(EntityState.Modified), InsertMode: false);
}
internal static class AuditingHelperUtility
{
internal static void ProcessAuditFields(IEnumerable<Object> list, bool InsertMode = true)
{
foreach (var item in list)
{
IAuditable entity = item as IAuditable;
if (entity != null)
{
if (InsertMode)
{
entity.InsertedBy = GetUserId();
entity.InsertedOn = DateTime.Now;
}
entity.UpdatedBy = GetUserId();
entity.UpdatedOn = DateTime.Now;
}
}
}
}
Sadly this is not possible with EF v1

Resources