I am using nopcommerce for my web shop and I am using Tasks that are getting information from an external system when an order has been shipped. When it is shipped I want to capture the payment and then set it as shipped. However, I keep getting EF errors. Any way to get around this for now? I need to have it up and running
An entity object cannot be referenced by multiple instances of IEntityChangeTracker.
See my code below:
int orderId = PBSManager.GetOrderIdByCustomOrderNumber(customOrderNumber);
NopObjectContext db = ObjectContextHelper.CurrentObjectContext;
Order order = db.Orders.SingleOrDefault(c => c.OrderId == orderId);
//Incorrect order id
if (order == null)
{
//Skip this one if we cannot find the id
continue;
}
if (OrderManager.CanCapture(order))
{
string error = string.Empty;
OrderManager.Capture(order, ref error);
if (!string.IsNullOrEmpty(error))
{
PBSManager.HandleCaptureError(order, error);
return;
}
}
if (OrderManager.CanShip(order))
{
OrderManager.Ship(order.OrderId, true);
}
I am just guessing that probably you are creating another context in the OrderManager class. You should use the same context.
Can this link be of any help
Multiple instances of context
Doesn't nopCommerce store the current context in the HttpContext, have you tried looking for it in there?
Related
I need to be able to only execute my code upon the condition that the related opportunity has a statecode of 1
In my code I am able to use the GenerateSalesOrderFromOpportunityRequest class provided by the Microsoft Dynamics SDK to create a new sales order when a opportunityclose activity is created.
The drawback of this approach is that an opportunityclose activity is created by the system when an opportunity is closed as won(1) or lost(2). Also, there are no attributes on the opportunityclose activity that say if it was won or lost. So the only way to find it out is to get that attribute from the related opportunity.
In my code I'm able to get other attributes from the related opportunity, like name, but I have not been able to get any other value for statecode other that 0.
Here is my code:
Entity postImageEntity = (context.PostEntityImages != null && context.PostEntityImages.Contains(this.postImageAlias)) ? context.PostEntityImages[this.postImageAlias] : null;
if (postImageEntity.LogicalName == "opportunityclose" && postImageEntity.Attributes.Contains("opportunityid") && postImageEntity.Attributes["opportunityid"] != null)
{
// Create an entity reference for the related opportunity to get the id for the GenerateSalesOrderFromOpportunityRequest class
EntityReference entityRef = (EntityReference)postImageEntity.Attributes["opportunityid"];
// Retrieve the opportunity that the closed opportunity activity was created for.
Entity RelatedEntityRef = service.Retrieve("opportunity", entityRef.Id, new ColumnSet( new String[] {"statecode","statuscode", "name"}));
OptionSetValue StateCode = (OptionSetValue)RelatedEntityRef.Attributes["statecode"];
OptionSetValue StatusCode = (OptionSetValue)RelatedEntityRef.Attributes["statuscode"];
string OppName = (string)RelatedEntityRef.Attributes["name"];
if (entityRef.LogicalName == "opportunity" && StateCode.Value == 1)
{
try
{
GenerateSalesOrderFromOpportunityRequest req = new GenerateSalesOrderFromOpportunityRequest();
req.OpportunityId = entityRef.Id;
req.ColumnSet = new ColumnSet(true);
GenerateSalesOrderFromOpportunityResponse resp = (GenerateSalesOrderFromOpportunityResponse)service.Execute(req);
}
catch (FaultException ex)
{
throw new InvalidPluginExecutionException("An error occurred in the plug-in.", ex);
}
}
}
Recap: For this to work I just need to be able to get the actual statecode value of the opportunity related to the opportunityclose. Currently I have only been able to get 0 even if I know that the state code of the opportunity is 1.
Other Info:
This is for Microsoft Dynamics Online 2013/2015(works with both)
Using SKD v6.1.1
Plugin works, but fires whether the opportunity is won or lost. (not intended)
Can't you view the opportunity to see if the status is won or lost. I
You can retrieve the OpportunityClose and change the status if you need to
https://msdn.microsoft.com/en-us/library/gg334301.aspx
I assume it's setting the opportunityclose to 1 because you are executing GenerateSalesOrderFromOpportunityRequest which you would only do if you won the opportunity (e.g. you wouldn't progress a lost opportunity).
i'm a beginner at developing a whole system so, need some approach guidance here folks. Hope you can help me! =)
In a try to create a log in schema, i have a Control class which keeps a list of logged users.
public static class ControleAcesso
{
private static List<Associado> associadosLogados = new List<Associado>();
public static Mensagens doLogin(Page pagina, String login, String senha)
{
Mensagens retorno = new Mensagens();
retorno = AcessoDAL.Login(login, senha);
if (retorno.Erros.Count() <= 0 && retorno.Objeto != null)
{
Associado assocLogado = new Associado();
Associados assocEncontrado = (Associados)retorno.Objeto;
assocLogado.ID = assocEncontrado.Associado;
assocLogado.Nome = assocEncontrado.Nome;
assocLogado.Nome_Fantasia = assocEncontrado.Nome_Fantasia;
assocLogado.Data_Inclusao = assocEncontrado.Data_Inclusao;
assocLogado.Email = assocEncontrado.Email;
assocLogado.Data_Alteracao = assocEncontrado.Data_Alteracao;
assocLogado.Login = assocEncontrado.Login;
assocLogado.Senha = assocEncontrado.Senha;
assocLogado.CGC_CPF = assocEncontrado.CGC_CPF;
assocLogado.SessionID = pagina.Session.SessionID;
var associadoJaLogado = associadosLogados.Where(x => x.ID == assocLogado.ID).FirstOrDefault();
if (associadoJaLogado != null)
{
pagina.Session.Remove(associadoJaLogado.SessionID);
associadosLogados.Remove(associadoJaLogado);
}
associadosLogados.Add(assocLogado);
}
return retorno;
}
}
So, this method basicaly do the login call to a Data Access Layer class. If the log in returns a user, i do Add this user to my list.
So, to later know my logged in users and retrieve data about then just using my session ID, i do some management in the list. Just the basic. Removing the logged in one and adding the new one.
The problem, as you probably noticed, is that, when i have two requests for the same credentials at the "same" time, it would allow the user to log in two times.
So, is this the best practice for log in schemes? Would you guys suggest me to change something?
I'm using ASP.NET Web Forms with C#.
Thank you in advice.
Unless you explicitly want to force your users to use your application with one device at a time, you should not worry about the possibility that they might log in. So this is a problem if and only if it can violate one of your terms.
I am writing a asp.net mvc4 app and I am using entity framework 5. Each of my entities have fields like EnteredBy, EnteredOn, LastModifiedBy and LastModifiedOn.
I am trying to auto-save them by using the SavingChanges event. The code below has been put together from numerous blogs, SO answeres etc.
public partial class myEntities : DbContext
{
public myEntities()
{
var ctx = ((IObjectContextAdapter)this).ObjectContext;
ctx.SavingChanges += new EventHandler(context_SavingChanges);
}
private void context_SavingChanges(object sender, EventArgs e)
{
ChangeTracker.DetectChanges();
foreach (ObjectStateEntry entry in
((ObjectContext)sender).ObjectStateManager
.GetObjectStateEntries
(EntityState.Added | EntityState.Modified))
{
if (!entry.IsRelationship)
{
CurrentValueRecord entryValues = entry.CurrentValues;
if (entryValues.GetOrdinal("LastModifiedBy") > 0)
{
HttpContext currContext = HttpContext.Current;
string userName = "";
DateTime now = DateTime.Now;
if (currContext.User.Identity.IsAuthenticated)
{
if (currContext.Session["userId"] != null)
{
userName = (string)currContext.Session["userName"];
}
else
{
userName = currContext.User.Identity.Name;
}
}
entryValues.SetString(
entryValues.GetOrdinal("LastModifiedBy"), userName);
entryValues.SetDateTime(
entryValues.GetOrdinal("LastModifiedOn"), now);
if (entry.State == EntityState.Added)
{
entryValues.SetString(
entryValues.GetOrdinal("EnteredBy"), userName);
entryValues.SetDateTime(
entryValues.GetOrdinal("EnteredOn"), now);
}
else
{
string enteredBy =
entry.OriginalValues.GetString(entryValues.GetOrdinal("EnteredBy"));
DateTime enteredOn =
entry.OriginalValues.GetDateTime(entryValues.GetOrdinal("EnteredOn"));
entryValues.SetString(
entryValues.GetOrdinal("EnteredBy"),enteredBy);
entryValues.SetDateTime(
entryValues.GetOrdinal("EnteredOn"), enteredOn);
}
}
}
}
}
}
My problem is that entry.OriginalValues.GetString(entryValues.GetOrdinal("EnteredBy")) and entry.OriginalValues.GetDateTime(entryValues.GetOrdinal("EnteredOn")) are not returning the original values but rather the current values which is null. I tested with other fields in the entity and they are returning the current value which were entered in the html form.
How do I get the original value here?
I think the problem may be that you are using the instance provided by the model binder as the input to your controller method, so EF does not know anything about that entity and its original state. Your code may look like this:
public Review Update(Review review)
{
_db.Entry(review).State = EntityState.Modified;
_db.SaveChanges();
return review;
}
In that case, EF knows nothing about the Review instance that is being saved. It is trusting you and setting it as modified, so it will save all of its properties to the database, but it does not know the original state\values of that entity.
Check the section named Entity States and the Attach and SaveChanges Methods of this tutorial. You can also check the first part of this article, that shows how EF does not know about the original values and will update all properties in the database.
As EF will need to know about the original properties, you may first load your entity from the database and then update its properties with the values received in the controller. Something like this:
public Review Update(Review review)
{
var reviewToSave = _db.Reviews.SingleOrDefault(r => r.Id == review.Id);
//Copy properties from entity received in controller to entity retrieved from the database
reviewToSave.Property1 = review.Property1;
reviewToSave.Property2 = review.Property2;
...
_db.SaveChanges();
return review;
}
This has the advantage that only modified properties will be send and updated in the database and that your views and view models don't need to expose every field in your business objects, only those that can be updated by the users. (Opening the door for having different classes for viewModels and models\business objects). The obvious disadvantage is that you will incur an additional hit to the database.
Another option mentioned in the tutorial I referenced above is for you to save the original values somehow (hidden fields, session, etc) and on save use the original values to attach the entity to the database context as unmodified. Then update that entity with the edited fields. However I would not recommend this approach unless you really need to avoid that additional database hit.
Hope that helps!
I was running into a similar problem when trying to audit log the Modified values of an Entity.
It turns out during the post back the ModelBinder doesn't have access to the original values so the Model received is lacking the correct information. I fixed my problem by using this function which clones the current values, relods the object, and then reset the current values.
void SetCorrectOriginalValues(DbEntityEntry Modified)
{
var values = Modified.CurrentValues.Clone();
Modified.Reload();
Modified.CurrentValues.SetValues(values);
Modified.State = EntityState.Modified;
}
You can gain access to the DbEntityEntry though the change tracker, or the entry function from your context.
i have developing project in c# for creating a user in AD.
i create a user and i want to create a attribute,like "mobilenumber"for this user.
when,i create this,the below error will occured.
here my code.
if (userDetails.GetUnderlyingObjectType() == typeof(DirectoryEntry))
{
dEntry = (DirectoryEntry)userDetails.GetUnderlyingObject();
if (User.UsrPassword != null && User.UsrPassword.Trim() != "")
{
if (dEntry.Properties.Contains("mobilenumber"))
{
Console.WriteLine("mobilenumberAttribute:Already created");
dEntry.Properties["mobilenumber"][0] = User.UsrPassword;
dEntry.CommitChanges();
}
else
{
Console.WriteLine("mobilenumber Attribute: Adding");
dEntry.Properties["mobilenumber"].Add(User.UsrPassword);
dEntry.CommitChanges();
}
userDetails.Save();
result = true;
}
}
The requested operation did not satisfy one or more constraints associated with the class of the object. (Exception from HRESULT: 0x80072014)
How can i resolve this?
Create an attribute? You mean like extending the schema? You can't do that by just adding it to an object. As you can see here, there is no such attribute as "mobilenumber". Maybe you want otherMobile (Phone-Mobile-Other) or mobile (Phone-Mobile-Primary)?
What are you trying to do? Why keep a copy of the password in the user object. If the user changes it, your copy will not be updated. If you need it to somehow inform the user, do something different like infoming his supervisor... Just a thought.
I've read through at least a dozen other questions just like this one, but I am having trouble grasping some of this stuff.
I'm used to developing ASP.NET MVC3 with repositories and code-first entities linking to the entity framework.
I've recently switched to database-first ADO.NET with services development.
I find this to be very clean since I can access stuff through my foreign keys.
Anyway, my old save methods seem to be broken since I constantly get this error
An entity object cannot be referenced by multiple instances of
IEntityChangeTracker
So here's a look at my save action and my service:
Action:
[HttpPost]
public ActionResult AddReview(Review review, int id)
{
User loggedInUser = userService.GetUserByusername(User.Identity.Name);
review.WriterId = loggedInUser.UserId;
review.ProductId = id;
if (ModelState.IsValid)
{
reviewService.Save(review);
Product product = productService.GetProduct(id);
if(product.Quantity>=1)
product.Quantity--;
product.TimesBought++;
productService.UpdateRating(product, reviewService);
loggedInUser.GoldCoins -= product.Price;
Session["goldCoins"] = loggedInUser.GoldCoins;
userService.Save(loggedInUser);
productService.Save(product);
}
else
{
return View(review);
}
return RedirectToAction("Index", "Answers", new { reviewId = review.ReviewId });
Service:
public class ReviewService : Service<Review, CapstoneEntities>
{
...
public void Save(Review review)
{
using (var db = new CapstoneEntities())
{
if (review.ReviewId == 0)
{
db.Reviews.Add(review);
db.Entry(review).State = EntityState.Added;
}
else
{
db.Entry(review).State = EntityState.Modified;
}
db.SaveChanges();
}
}
}
My suspicion is with this line of code: using (var db = new CapstoneEntities()) but I'm not sure how else to do this. Again, this worked perfectly with my old way of doing things but now I get errors on just about ever CRUD operation.
Thank you.
It looks like this is being caused by having an entity belong to multiple DataContexts. Whatever code that is calling that action should use the same DataContext to create the entity as the one used to persist it to the datastore.
In most instances you should only keep one instance of the DataContext. You can use a DI framework like Castle to define/store a dependency (in this case the DataContext) as Transient or PerWebRequest and inject it into the service and controller, so you'll always have a reference to the same instance of the DataContext.
I am new to MVC & Entity frame work. I got same problem after fighting a lot
This solution worked for me. Hope it can be useful for you guys.
var mediaItem = db.MediaItems.FirstOrDefault(x => x.Id == mediaItemViewModel.Id);
mediaItem.Name = mediaItemViewModel.Name;
mediaItem.Description = mediaItemViewModel.Description;
mediaItem.ModifiedDate = DateTime.Now;
mediaItem.FileName = mediaItem.FileName;
mediaItem.Size = KBToMBConversion(mediaItemViewModel.Size);
mediaItem.Type = mediaItem.Type;
//db.Entry(mediaItem).State = EntityState.Modified;// coment This line
db.SaveChanges();
Cause you are reading the the whole object from db and holding it in the current context and when you try to modify the entity state its tells you already one entity attached to the current context. just call save changes it will save it.