I'm trying to do the tutorial here: http://www.asp.net/entity-framework/tutorials/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application
In the ActionResult Edit, I have the following code:
public ActionResult Edit(Product product)
{
try
{
if (ModelState.IsValid)
{
db.Entry(product).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
}
catch(DbUpdateConcurrencyException ex)
{
var entry = ex.Entries.Single();
var databaseValuesObj = entry.GetDatabaseValues().ToObject();
var databaseValues = (Product)databaseValuesObj;
var clientValues = (Product)entry.Entity;
if (databaseValues.Name != clientValues.Name)
ModelState.AddModelError("Name", "Current value: "
+ databaseValues.Name);
if (databaseValues.Description != clientValues.Description)
ModelState.AddModelError("Description", "Current value: "
+ String.Format("{0:c}", databaseValues.Description));
if (databaseValues.ControllingStudentId != clientValues.ControllingStudentId)
ModelState.AddModelError("ControllingStudentId", "Current value: "
+ String.Format("{0:d}", databaseValues.ControllingStudentId));
ModelState.AddModelError(string.Empty, "The record you attempted to edit "
+ "was modified by another user after you got the original value. The "
+ "edit operation was canceled and the current values in the database "
+ "have been displayed. If you still want to edit this record, click "
+ "the Save button again. Otherwise click the Back to List hyperlink.");
product.Timestamp = databaseValues.Timestamp;
}
catch (DataException)
{
//Log the error (add a variable name after Exception)
ModelState.AddModelError(string.Empty, "Unable to save changes. Try again, and if the problem persists contact your system administrator.");
}
return View(product);
}
On the var databaseValuesObj = entry.GetDatabaseValues().ToObject(); line, I get an exception like this:
System.Data.EntitySqlException was unhandled by user code
Message=Type 'MvcApplication3.DAL.Product' could not be found. Make sure that the required schemas are loaded and that the namespaces are imported correctly. Near type name, line 1, column 119.
Source=System.Data.Entity
Column=119
ErrorContext=type name, line 1, column 119
ErrorDescription=Type 'MvcApplication3.DAL.Product' could not be found. Make sure that the required schemas are loaded and that the namespaces are imported correctly.
Line=1
...
My question is, how can I show it where the Product class is? Its in the project and I've got the using statement at the top. Why can't it find it?
Edit:
Based on the response below, I changed my code to:
var entry = ex.Entries.Single();
var currentValues = entry.CurrentValues.Clone();
entry.Reload();
entry.CurrentValues.SetValues(currentValues);
var clientValues = (Product)entry.Entity;
var databaseValues = (Product)entry.OriginalValues.ToObject();
And that seemed to fix it. But I think it will have issues if the row is deleted. My current problem won't have that issue, so this is a good fix for me. Thanks!
This is a known issue when the context is in a different projects. No workarounds currently exist except for moving the context into the same project.
http://social.msdn.microsoft.com/Forums/en-HK/adodotnetentityframework/thread/fa67aa0e-3bca-44a5-9e00-af6362a539a7
EDIT
Actually I take that back - there is a workaround now listed there since the last time I read this. cool : )
Related
I've tried a few different ways to do this and each way has a piece of code I am just not getting right. I need to update a custom field UsrCustomerShipAccount in Customer Locations if it is updated in the Customer Delivery Tab. I tried SetValueExt and creating a graph instance. Sorry about the dumb question.
The way that seemed to get me the closest is below:
protected void LocationExtAddress_UsrCustomerShipAccnt_FieldUpdated(PXCache cache, PXFieldUpdatedEventArgs e, PXFieldUpdated InvokeBaseHandler)
{
if(InvokeBaseHandler != null)
InvokeBaseHandler(cache, e);
var row = (LocationExtAddress)e.Row;
if (row == null) return;
PXSelectBase<Location> locationObj = new PXSelect<Location, Where<Location.bAccountID, Equal<Required<Location.bAccountID>>>>(Base);
Location deliveryLocation = locationObj.Select(row.LocationBAccountID);
var locationExt = PXCache<Location>.GetExtension<LocationExt>(location); <-- This generates error that there is no LocationExt.
deliveryLocation.Cache.SetValueExt(deliveryLocation, "UsrCustomerShipAccount", -->This needs to be the value that changed LocationExtAddress.UsrCustomerShipAccount but I don't see how to get this<--);
deliveryLocation.Cache.IsDirty = true;
deliveryLocation.Update(deliveryLocation); <--I don't know if this doesn't work because it is wrong or if it is because "UsrCustomerShipAccount" is not in deliverLocation.
}
You have
var locationExt = PXCache<Location>.GetExtension<LocationExt>(location);
shouldn't this be
var locationExt = PXCache<Location>.GetExtension<LocationExt>(deliveryLocation );
?
I am trying to parse recurrence rule string to telerik object but it does not work for me at all. The result is always null even though the string pattern seems to be right (passed from Kendo Recurrence control). Thank you for any thoughts on this.
Update: I tried another case to prove if the parse is working or not, here is the result:
As per this post http://www.telerik.com/forums/parsing-recurrencerule-server-side recurrence rule works when INTERVAL is specified.
As to the exceptions thrown by RecurrenceRule.TryParse, I noticed that
it is caused when INTERVAL rule is missing. If you want to use the
RecurrenceRule.TryParse method, you will need to add it manually.
here is the modified code that was originally uploaded by jonno
var today = DateTime.Now.Date;
var start = today.AddDays(-14).AddHours(19);
var end = start.AddHours(2.5);
// Create a few recurring events using Kendo Web Scheduler and use the recurrence rules
var patterns = new[]
{
"FREQ=DAILY;UNTIL=20140227T130000Z",
"FREQ=DAILY;INTERVAL=3;UNTIL=20140227T130000Z",
"FREQ=DAILY;INTERVAL=3;COUNT=4",
"FREQ=DAILY;INTERVAL=5",
"FREQ=WEEKLY;BYDAY=WE;INTERVAL=1",
"FREQ=WEEKLY;COUNT=5;BYDAY=TU,WE;INTERVAL=1",
"FREQ=WEEKLY;INTERVAL=4;COUNT=5;BYDAY=WE,TH,SA",
"FREQ=WEEKLY;INTERVAL=3;UNTIL=20140331T090000Z;BYDAY=WE,TH,SA",
"FREQ=MONTHLY;BYMONTHDAY=13;INTERVAL=1",
"FREQ=MONTHLY;COUNT=7;BYDAY=1FR;INTERVAL=1",
"FREQ=MONTHLY;UNTIL=20150212T130000Z;BYDAY=SU,SA;BYSETPOS=-1;INTERVAL=1",
"FREQ=YEARLY;BYMONTH=12;BYMONTHDAY=25",
"FREQ=YEARLY;COUNT=3;BYMONTH=2;BYMONTHDAY=28",
"FREQ=YEARLY;UNTIL=20200306T130000Z;BYMONTH=8;BYDAY=3WE",
"FREQ=WEEKLY;COUNT=5;BYDAY=MO;INTERVAL=4",
"FREQ=WEEKLY;COUNT=2;BYDAY=MO;INTERVAL=1",
};
// Now figure out which events will trigger in the next week - server side only - using Telerik.Web.UI.dll RecurrenceRule class.
foreach (var expr in patterns)
{
var rrule = string.Format("DTSTART:{0:yyyyMMddTHHmmssZ}\r\nDTEND:{1:yyyyMMddTHHmmssZ}\r\nRRULE:{2}", start, end, expr);
try
{
RecurrenceRule recRule = null;
var b = RecurrenceRule.TryParse(rrule, out recRule);
if (recRule == null)
{
Console.WriteLine("PARSE ERROR: " + expr);
continue;
}
}
catch (Exception)
{
Console.WriteLine("PARSE ERROR: " + expr);
}
}
Unless someone can explain what I'm missing, CRM 2013 does not have any way to check for a duplicate WHILE entering a new Lead record. I want to check for a duplicate BEFORE the new record is saved. I can't seem to figure this one out.
Basically, when a user enters the Company Name on a new Lead record, I'd like JavaScript or something check for the existence of that value in all the other Lead records and return True or False. That way I can alert the user that the Company already exists BEFORE they save the new record.
Make sense? Am I just TOTALLY missing something here?
Thanks,
Scotty
Microsoft removed this functionality. But you can restore it using one of following articles:
http://a33ik.blogspot.com/2013/10/how-to-turn-on-duplicate-detection-for.html
http://jlattimer.blogspot.com/2013/10/are-you-missing-duplicate-detection-in.html
You can use below function to check duplicate records and set alert/field value depending upon result set :
CheckDuplicate: function (someIdentifier) {
var value = null;
var filter = "?$select=*&$filter=(new_Identifier eq '" + someIdentifier + "') and (new_someGuidField/Id eq guid'" + Xrm.Page.getAttribute("new_someGuidField").getValue()[0].id + "')";
retrieveMultipleSync("new_EntityNameSet", filter, function (data, textStatus, XmlHttpRequest) {
if (data != null && data.length > 0) {
value = data;
}
}, null);
return value;
}
I have this Google Apps Script to send an email with a request to people I choose in a spreadsheet:
function sendRequestEmail() {
var data = SpreadsheetApp.openById(SPREADSHEET);
if(!employee_ID) {
employee_ID = getCurrentRow();
if (employee_ID == 1) {
var employee_ID = Browser.inputBox("VocĂȘ precisa selecionar um assistido?", "Choose a row or type its number here:", Browser.Buttons.OK_CANCEL);
}
}
// Fetch variable names
// they are column names in the spreadsheet
var sheet = data.getSheets()[0];
var columns = getRowAsArray(sheet, 1);
Logger.log("Processing columns =" + columns);
var employeeData = getRowAsArray(sheet, employee_ID);
Logger.log("Processing employeeData = " + employeeData);
// Assume first column holds the name of the person
var email2Send = "pythonist#example.com";
var title = "Request by email";
var name = employeeData[0];
var mother_name = employeeData[1];
var message = "Hi, I have a request for you, " + name + ", this is... example";
// HERE THE
// CONFIRMATION BUTTON!!!
MailApp.sendEmail(email2Send, title, message);
}
And, before sending the email, I want a confirmation button, something like this:
function showConfirmation(name, email2Send) {
var app = UiApp.createApplication().setHeight(150).setWidth(250);
var msg = "Do you confirm the request to " + email2Send + " about " + name + "?";
app.setTitle("Confirmation of request");
app.add(app.createVerticalPanel().add(app.createLabel(msg)));
var doc = SpreadsheetApp.getActive();
doc.show(app);
}
So, if user press OK, the app will execute the line MailApp.sendEmail(email2Send, title, message); and send an e-mail.
I have to admit my ignorance. I'm reading chapter 4 of the book "Google Apps Script" (Oreilly, by James Ferreira) on handlers. I've tried using an example provided in the documentation from Google (already deleted the code!). But I came across an error that I could not understand.
The code used were this sample:
var ui = DocumentApp.getUi();
var response = ui.prompt('Getting to know you', 'May I know your name?', ui.ButtonSet.YES_NO);
// Process the user's response.
if (response.getSelectedButton() == ui.Button.YES) ... DO THIS
I have some urgency in this simple project, so forgive-me for asking this question before research more for the answer (I'm searching for it while wating for the answer). So, how can I use a confirmation/cancellation button in this code?
The code snippet you showed is for document embedded UI, the equivalent (well... almost) class for spreadsheet context is Browser.MsgBox(prompt,buttons), see doc here, it will be simpler than create a Ui + a handler function... even if the layout and appearance are fairly basic it's easy and efficient.
In your code it becomes :
...
var confirm = Browser.msgBox('send confirmation','Are you sure you want to send this mail ?', Browser.Buttons.OK_CANCEL);
if(confirm=='ok'){ MailApp.sendEmail(email2Send, title, message)};
...
In my Edit Controller Action, I post the object to update.
[HttpPost]
public virtual ActionResult Edit(Case myCase){
var currentDocuments = db.CaseDocuments.Where(p => p.idCase == myCase.idCase);
foreach (CaseDocument docInDB in currentDocuments )
{
var deleteDoc = true;
foreach (CaseDocument docNew in myCase.CaseDocuments )
{
if (docNew.idDocument == docInDB.idDocument)
deleteDoc = false;
}
if (deleteDoc )
db.CaseDocuments.Remove(docInDB);
}
foreach (CaseDocument pc in myCase.CaseDocuments)
{
if (pc.idDocument == 0)
db.CaseDocuments.Add(pc);
else
db.Entry(pc).State = EntityState.Modified;
}
*** **db.Entry(myCase).State = EntityState.Modified;** //THIS LINE
db.SaveChanges();
}
The Case model has a collection of Documents, and they are posted along with the Case Model.
As soon I enter the action, I can count the number of documents in the collection, and lets say there are 3.
Then, in order to see if I need to delete documents from database (as the user deleted one from UI), I need to get the Documents for that case from database in this way:
var currentDocuments = db.CaseDocuments.Where(p => p.idCase == myCase.idCase);
And here starts the weird thing: as soon I executa that statement, the myCase.Documents is loaded with what it is in database (lets say there are 4)!! So, I'm not able to compare the 2 collections (to detect if a document was deleted and remove it from db).
What I need is during the Edit Action of my Case model, I need to create/update/modify its documents. Do I need to see this from other angle? What I'm doing is wrong?
EDIT:
After the comments, I realized that the line where I marked myCase as Modified, was at the begining, and I suppose that this was the reason for that behaviour.
Now, moving that line to just before the db.SaveChanges(), fixed that problem, but at the db.Entry(myCase).State = EntityState.Modified; says "There is already an object with the same key in ObjectStateManager. "
What am I doing wrong here? This code looks bad!
Try it this way:
[HttpPost]
public virtual ActionResult Edit(Case myCase){
var currentDocumentIds = db.CaseDocuments
.Where(p => p.idCase == myCase.idCase)
.Select(p => p.idDocument);
foreach (int idInDb in currentDocumentsIds.Where(i => !myCase.CaseDocuments
.Any(ci => ci.idDocumnet == i))
{
var docToDelete = new CaseDocument { idDocument = idInDb };
db.CaseDocuments.Remove(docToDelete);
}
foreach (CaseDocument pc in myCase.CaseDocuments)
{
if (pc.idDocument == 0)
db.CaseDocuments.Add(pc);
else
db.Entry(pc).State = EntityState.Modified;
}
db.Entry(myCase).State = EntityState.Modified;
db.SaveChanges();
}
Edit: The difference between this code and your code is the way how it works with existing documents. It doesn't load them - it loads just their ids. This way you will save some data transfer from database but it should also help you avoiding that exception. When you load the document from the database you have it already attached in the context but if you try to call this:
db.Entry(pc).State = EntityState.Modified;
you will try to attach another instance of the document with the same key to the context. That is not allowed - context can have attached only single instance with unique key.