An object with the same key already exists in the ObjectStateManage - linq

I have a repository model method:-
public void InsertOrUpdateServer(TMSServer server, string username,long assetid)
{
var resource = GetResourceDetials(assetid);
if (server.ServerID == default(int))
{
//code goes here>>>>>>>>.......>>>
}
else
{
// Existing entity
var auditinfo = IntiateAudit(
tms.AuditActions.SingleOrDefault(
a => a.Name.ToUpper() == "EDIT").ActionID,
tms.TechnologyTypes.SingleOrDefault(
a => a.Name.ToUpper() == "Server").AssetTypeID,
username, server.ServerID
);
server.IT360SiteID = resource.SITEID.Value;
tms.Entry(server).State = EntityState.Modified; // this will raise the esception
InsertOrUpdateAudit(auditinfo);
}
}
but when this method is call i will get the folloiwng exception on :-
tms.Entry(server).State = EntityState.Modified;
An object with the same key already exists in the ObjectStateManager.
The ObjectStateManager cannot track multiple objects with the same
key. Description: An unhandled exception occurred during the
execution of the current web request. Please review the stack trace
for more information about the error and where it originated in the
code.
Exception Details: System.InvalidOperationException: An object with
the same key already exists in the ObjectStateManager. The
ObjectStateManager cannot track multiple objects with the same key.
Source Error: Line 1046: username, server.ServerID);
Line 1047: server.IT360SiteID =
resource.SITEID.Value;///// Line 1048:
tms.Entry(server).State = EntityState.Modified; Line 1049:
// tms.Entry(technologyIP).State = EntityState.Modified; Line 1050:
InsertOrUpdateAudit(auditinfo);
So i can not figure out what is causing this isssue , since i am only tracking one object named servev ?? can anyone advice on what is going on ?

Related

Unable to cast object of type CRM 2013 Plugin

I have a Synchronous plugin that runs when any opportunity create/delete/update. And in Plugin if any error comes i have made a function which insert log into database.
In table one field if EntityId, so i am writing the following code :
foreach (PropertyBagEntry entry in (IEnumerable<PropertyBagEntry>)context.InputParameters.Values)
{
DynamicEntity entity = (DynamicEntity)entry.Value;
foreach (Property property in (IEnumerable<Property>)entity.Properties)
{
if (property.GetType().Name == "KeyProperty")
{
str4 = ((Key)entity.Properties[property.Name]).Value.ToString();
break;
}
}
}
In str4 i am getting EntityId of current process.
But it gives one exception very frequently :
Unhandled Exception: System.InvalidCastException: Unable to cast object of type
'ValueCollection[System.String,System.Object]'
to type 'System.Collections.Generic.IEnumerable`1[Microsoft.Crm.Sdk.PropertyBagEntry]'
And i have identified that the following line is giving error
foreach (PropertyBagEntry entry in (IEnumerable)context.InputParameters.Values)
Anyone have idea to convert this line in another way ?
My understanding is that you want to get the GUID of current record, if this is the case then you can do it as:
public void Execute(IServiceProvider serviceProvider)
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
try
{
if (context.MessageName == "Create" || context.MessageName == "Update")
{
if (context.InputParameters.Contains("Target") && (context.InputParameters["Target"] is Entity))
{
Entity currentEntity = (Entity) context.InputParameters["Target"];
Guid currentRecordGuid = currentEntity.Id;
}
}
}
catch (Exception ex)
{
}
}
I believe the type of that collection varies from one message to another. If you are looking to get the Id of the record within a plugin, this helper function may come in handy:
public static Guid GetEntityIdFromContext(IPluginExecutionContext context)
{
string messageName = context.MessageName;
if (context.PrimaryEntityId != Guid.Empty)
{
return context.PrimaryEntityId;
}
else if (messageName == "Create")
{
return new Guid(context.OutputParameters["id"].ToString());
}
else
{
return context.PrimaryEntityId;
}
}
If that doesn't help, would you mind providing the message that causes the error?
If
Unhandled Exception: System.InvalidCastException: Unable to cast
object of type 'ValueCollection[System.String,System.Object]' to type
'System.Collections.Generic.IEnumerable`1[Microsoft.Crm.Sdk.PropertyBagEntry]'
is truly your error, than your issue is not with line
foreach (Property property in (IEnumerable<Property>)entity.Properties)
but with line:
foreach (PropertyBagEntry entry in (IEnumerable<PropertyBagEntry>)context.InputParameters.Values)
The type of context.InputParameters.Values is not castable to an IEnumerable

LINQ Any method breaks NHibernate initialization

I have a wired problem in my ASP.NET MVC application using NHibernate.
There is a virutal method named IsLeaderBanker(IbEmployee banker) in my domain model. The impelementaion is like this:
public virtual bool IsLeaderBanker(IbEmployee banker)
{
return GetLeaderBankers().Any(lb => lb.Id == banker.Id);
}
It is simple and smooth. However, Nhibernate throws an Exception when initializing SessionStorage.
The entity '<>c__DisplayClass9' doesn't have an Id mapped. Use the Id method to map your identity property. For example: Id(x => x.Id).
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: FluentNHibernate.Visitors.ValidationException: The entity '<>c__DisplayClass9' doesn't have an Id mapped. Use the Id method to map your identity property. For example: Id(x => x.Id).
Source Error:
Line 144: storage = new WebSessionStorage(this);
Line 145: NHibernateInitializer.Instance().InitializeNHibernateOnce(
Line 146: () => NHibernateSession.Init(storage,
Line 147: new[] { Server.MapPath(#"~/bin/IB.Oss.Dal") },
Line 148: AutoPersistenceModelGenerator.Generate(
After tried quite a lot of guesses and tests, I found it is the LINQ Any method made it crash. Which is, if I rewrite it like this:
public virtual bool IsLeaderBanker(IbEmployee banker)
{
var result = GetLeaderBankers();
foreach (var b in result)
{
if (b.Id == banker.Id)
{
return true;
}
}
return false;
}
Everything works. This is the same logic and Reshaper suggests me to change it to LINQ. Why the Any method breaks NHibernate? I use Where and Select many times and they all work fine.
The Nhibernate Version is 3.3.2 in my application.
Try this:
public virtual bool IsLeaderBanker(IbEmployee banker)
{
var id = banker.Id;
return GetLeaderBankers().Any(lb => lb.Id == id);
}

How i can force the entity framework to raise a unique exception if the Unique key constraint has been violated on thr sql server database

I have a table named countries and i define the country_name field to be unique by creating a “Index/Key” of type “Unique Key” on sql servwer 2008 r2.
But currently if the user insert a country_name value that already exists on my asp.net mvc3 application, then an exception of type “System.Data.Entity.Infrastructure.DbUpdateException” will be raised , which is very general.
So is there a way to define a specific exception in case the unique constraint has been violated ??? rather than just raising the general “System.Data.Entity.Infrastructure.DbUpdateException” exception?
BR
Most likely, thought I can't test it at the moment, the inner exception of DbUpdateException is probably an exception about a duplicate or foreign key constraint. More importantly, you have an opportunity to not throw any exceptions by checking to see if a country already exists. Two ways I can think of are to; check and see if the country already exists by doing a simple select, and if it doesn't, doing an insert/add or write a stored procedure that and do a select/insert or merge and return any value(s) you want back.
Update
(this is example code to demonstrate the logic flow of events and not good programming practice, specially by catching all excepts)
Exception Logic
public AddCountry(string countryTitle)
{
using (var db = new DbContext(_connectionString)
{
try
{
// Linq to (SQL/EF)-ish code
Country country = new Country();
country.ID = Guid.NewGuid();
country.Title = countryTitle;
db.Countrys.Add(country);
db.SubmitChanges(); // <--- at this point a country could already exist
}
catch (DbUpdateException ex)
{
// <--- at this point a country could be delete by another user
throw Exception("Country with that name already exists");
}
}
}
Non-Exception Logic
public AddCountry(string countryTitle)
{
using (var db = new DbContext(_connectionString)
{
using (TransactionScope transaction = new TransactionScope())
{
try
{
Country country = db.Countries
.FirstOrDefault(x => x.Title = countryTitle);
if (country == null)
{
country = new Country();
country.ID = Guid.NewGuid();
country.Title = countryTitle;
db.Countrys.Add(country);
db.SubmitChanges(); // <--- at this point a country
// shouldn't exist due to the transaction
// although someone with more expertise
// on transactions with entity framework
// would show how to use transactions properly
}
}
catch (<someTimeOfTransactionException> ex)
{
// <--- at this point a country with the same name
// should not exist due to the transaction
// this should really only be a deadlock exception
// or an exception outside the scope of the question
// (like connection to sql lost, etc)
throw Exception("Deadlock exception, cannot create country.");
}
}
}
}
Most likely the TransactionScope(Transaction transactionToUse) Constructor would be needed and configured properly. Probably with an Transactions.IsolationLevel set to Serializable
I would also recommend reading Entity Framework transaction.

Could this be a bug?

I have the following test case
[TestMethod()]
[DeploymentItem("Courses.sdf")]
public void RemoveCourseConfirmedTest()
{
CoursesController_Accessor target = new CoursesController_Accessor();
int id = 50;
ActionResult actual;
CoursesDBContext db = target.db;
Course courseToDelete = db.Courses.Find(id);
List<CourseMeet> meets = courseToDelete.meets.ToList<CourseMeet>();
actual = target.RemoveCourseConfirmed(courseToDelete);
foreach (var meet in meets)
{
Assert.IsNull(db.Meets.find(meet));
}
Assert.IsNull(db.Courses.Find(courseToDelete.courseID));
}
Which tests the following method from my controller.
[HttpPost, ActionName("RemoveCourse")]
public ActionResult RemoveCourseConfirmed(Course course)
{
try
{
db.Entry(course).State = EntityState.Deleted;
db.SaveChanges();
return RedirectToAction("Index");
}
catch (DbUpdateConcurrencyException)
{
return RedirectToAction("RemoveMeet", new System.Web.Routing.RouteValueDictionary { { "concurrencyError", true } });
}
catch (DataException)
{
ModelState.AddModelError(string.Empty, "Unable to save changes. Try again.");
return View(course);
}
}
I know i should be using a Mock db .... but for this project I have decided to go with this approach.
So this what happens. When I run the actual web site this function works perfectly fine and removes the course and all the meets that belong to it.
But when I run the test i get the following exception
System.InvalidOperationException: The operation failed: The relationship could not be
changed because one or more of the foreign-key properties is non-nullable. When a change is
made to a relationship, the related foreign-key property is set to a null value. If the
foreign-key does not support null values, a new relationship must be defined, the foreign-
key property must be assigned another non-null value, or the unrelated object must be
deleted.
Here is the even more interesting part if I comment out the following line from the test
List<CourseMeet> meets = courseToDelete.meets.ToList<CourseMeet>();
and replace the loop with the following:
foreach (var meet in db.Meets.ToList())
{
Assert.IsFalse(meet.courseID == courseToDelete.courseID);
}
I dont get any exceptions and the test case passess.
Am I missing something about Entity Framework or is this a bug?
Well this has been open for a while now. I still haven't been able to find a definite answer but working more with MVC and EF i think what is happening is that once i execute the line
List<CourseMeet> meets = courseToDelete.meets.ToList<CourseMeet>();
the meets get loaded into the object manager and hence when the parent object is deleted the no longer have a reference to the parent course.

PrepareResponse().AsActionResult() throws unsupported exception DotNetOpenAuth CTP

Currently I'm developing an OAuth2 authorization server using DotNetOpenAuth CTP version. My authorization server is in asp.net MVC3, and it's based on the sample provided by the library. Everything works fine until the app reaches the point where the user authorizes the consumer client.
There's an action inside my OAuth controller which takes care of the authorization process, and is very similar to the equivalent action in the sample:
[Authorize, HttpPost, ValidateAntiForgeryToken]
public ActionResult AuthorizeResponse(bool isApproved)
{
var pendingRequest = this.authorizationServer.ReadAuthorizationRequest();
if (pendingRequest == null)
{
throw new HttpException((int)HttpStatusCode.BadRequest, "Missing authorization request.");
}
IDirectedProtocolMessage response;
if (isApproved)
{
var client = MvcApplication.DataContext.Clients.First(c => c.ClientIdentifier == pendingRequest.ClientIdentifier);
client.ClientAuthorizations.Add(
new ClientAuthorization
{
Scope = OAuthUtilities.JoinScopes(pendingRequest.Scope),
User = MvcApplication.LoggedInUser,
CreatedOn = DateTime.UtcNow,
});
MvcApplication.DataContext.SaveChanges();
response = this.authorizationServer.PrepareApproveAuthorizationRequest(pendingRequest, User.Identity.Name);
}
else
{
response = this.authorizationServer.PrepareRejectAuthorizationRequest(pendingRequest);
}
return this.authorizationServer.Channel.PrepareResponse(response).AsActionResult();
}
Everytime the program reaches this line:
this.authorizationServer.Channel.PrepareResponse(response).AsActionResult();
The system throws an exception which I have researched with no success. The exception is the following:
Only parameterless constructors and initializers are supported in LINQ to Entities.
The stack trace: http://pastebin.com/TibCax2t
The only thing I've done differently from the sample is that I used entity framework's code first approach, an I think the sample was done using a designer which autogenerated the entities.
Thank you in advance.
If you started from the example, the problem Andrew is talking about stays in DatabaseKeyNonceStore.cs. The exception is raised by one on these two methods:
public CryptoKey GetKey(string bucket, string handle) {
// It is critical that this lookup be case-sensitive, which can only be configured at the database.
var matches = from key in MvcApplication.DataContext.SymmetricCryptoKeys
where key.Bucket == bucket && key.Handle == handle
select new CryptoKey(key.Secret, key.ExpiresUtc.AsUtc());
return matches.FirstOrDefault();
}
public IEnumerable<KeyValuePair<string, CryptoKey>> GetKeys(string bucket) {
return from key in MvcApplication.DataContext.SymmetricCryptoKeys
where key.Bucket == bucket
orderby key.ExpiresUtc descending
select new KeyValuePair<string, CryptoKey>(key.Handle, new CryptoKey(key.Secret, key.ExpiresUtc.AsUtc()));
}
I've resolved moving initializations outside of the query:
public CryptoKey GetKey(string bucket, string handle) {
// It is critical that this lookup be case-sensitive, which can only be configured at the database.
var matches = from key in db.SymmetricCryptoKeys
where key.Bucket == bucket && key.Handle == handle
select key;
var match = matches.FirstOrDefault();
CryptoKey ck = new CryptoKey(match.Secret, match.ExpiresUtc.AsUtc());
return ck;
}
public IEnumerable<KeyValuePair<string, CryptoKey>> GetKeys(string bucket) {
var matches = from key in db.SymmetricCryptoKeys
where key.Bucket == bucket
orderby key.ExpiresUtc descending
select key;
List<KeyValuePair<string, CryptoKey>> en = new List<KeyValuePair<string, CryptoKey>>();
foreach (var key in matches)
en.Add(new KeyValuePair<string, CryptoKey>(key.Handle, new CryptoKey(key.Secret, key.ExpiresUtc.AsUtc())));
return en.AsEnumerable<KeyValuePair<string,CryptoKey>>();
}
I'm not sure that this is the best way, but it works!
It looks like your ICryptoKeyStore implementation may be attempting to store CryptoKey directly, but it's not a class that is compatible with the Entity framework (due to not have a public default constructor). Instead, define your own entity class for storing the data in CryptoKey and your ICryptoKeyStore is responsible to transition between the two data types for persistence and retrieval.

Resources