Error add object in table contaning FK - c#

I create tow table in sql server 2008 with relationship 1 - * .
table 1: Tour (ID, date, ..) : ID : PK
table 2 : Position (ID,..) : ID : PK, and TourID : FK
Tour tour = new Tour() { ID = 17 /* this ID exist in table tou*/};
Position position = new Position();
position.Tour = tour;
position.Longitude = Longitude;
position.DateHeurePosition = DateH;
db.AttachTo("Tour", tour);
db.AddToPosition(position);
db.SaveChanges();
this error is displayed:
An object with the same key already exists in the ObjectStateManager.
The ObjectStateManager cannot track multiple objects with the same key
How to resolve this error?

In order to resolve this error, you need to make sure that the id that you are adding is unique.

What you did is that you created a new Tour with an ID that already exists.
In case you want to attach the position to the tour having ID=17, you have to get the record you want from the database:
Replace position.Tour = tour;
with position.Tour = db.Tour.FirstOrDefault(p=>p.ID==17);

You can solve this by detaching it first, there are some things you can do to Update the object by just setting the new values. Like this:
ObjectContext API: context.YourEntitySet.ApplyCurrentValues(newEntity);
DbContext API: context.Entry(oldEntity).CurrentValues.SetValues(newEntity);
I think the only thing you need here, is to find the attached item something like below
Tour t = Tours.Find(Id);//e.g. Id = 17 where Tours is the DbContext.Set<Tour>
position.Tour = t;
If you have another list of tours:
Tour t = Tours.First(i=> i.Id == Id);//e.g. Id = 17 where Tours is something with interface IEnumarable<Tour>
position.Tour = t;
And then set the values to the rest of that item.
But if you want to see a more complex implementation of update, here is my implementation of the update method:
public virtual void Update(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
var attachedEntity = DbSet.Find(entity.Id);
if (attachedEntity != null)
{
var attachedEntry = DbContext.Entry(attachedEntity);
entity.Created = attachedEntity.Created;
entity.LastModified = DateTime.Now;
attachedEntry.CurrentValues.SetValues(entity);
}
else
{
dbEntityEntry.State = EntityState.Modified;
entity.LastModified = DateTime.Now;
}
}
When you adjust it to your needs, you can pass the object to the method and then save the changes.

Related

Dynamics 365 (CRM) Version 9.1 online C# code Error: Entity Id must be the same as the value set in property bag

When cloning/copying child records, I use a foreach loop and then create a record with all its attributes. I wrote similar code in another project and worked fine for me.
There are multiple articles/questions based on the same Error. Now my issue is how should I create child records with all its attributes.
foreach (var packingList in oPEntityCollection.Entities)
{
packingList.Attributes.Remove("statuscode");
packingList.Attributes.Remove("statecode");
packingList.Id=Guid.Empty;
orgService.Create(packingList);
}
Another strange issue
An entry with the same key already exists
Code:
Entity parentEntity = orgService.Retrieve(context.PrimaryEntityName, context.PrimaryEntityId, new ColumnSet(true));
parentEntity.Id = Guid.empty;
orgService.Create(parentEntity);
Even if I create a new object and copy parentEntity just like below I get this error.
Entity costcalEntity = new Entity();
costcalEntity = parentEntity;
costcalEntity.Id = Guid.Empty;
orgService.Create(costcalEntity);
So I end up creating a record with primary name and once the record is created, I update the same record with old record attributes.
Entity costcalEntity = new Entity();
costcalEntity.LogicalName = parentEntity.LogicalName;
costcalEntity["name"] = parentQuotationEntity.GetAttributeValue<string>("name");
costcalEntity.Id = Guid.Empty;
Guid newGuid = orgService.Create(costcalEntity);
if (newGuid != Guid.Empty)
{
costcalEntity = parentEntity;
costcalEntity.Id = newGuid;
orgService.Update(costcalEntity);
}
and this works fine.
In both cases you have the same issue, with it's root cause being the Id stored in the attribute collection of the entity. If you look at the early bound generation, you can access the Id by the entity.Id property, as well as the attribute collection as shown in the definition for the id in the primary id:
public System.Nullable<System.Guid> AccountId
{
[System.Diagnostics.DebuggerNonUserCode()]
get
{
return this.GetAttributeValue<System.Nullable<System.Guid>>("accountid");
}
[System.Diagnostics.DebuggerNonUserCode()]
set
{
this.OnPropertyChanging("AccountId");
this.SetAttributeValue("accountid", value);
if (value.HasValue)
{
base.Id = value.Value;
}
else
{
base.Id = System.Guid.Empty;
}
this.OnPropertyChanged("AccountId");
}
}
So when you are retrieving an existing entity, both the Property Id, which you have handled, as well as the attribute collection, which you haven't handled, have been populated by the CRM SDK. So in order to be able to duplicate it, you'll need to clear the id in both places.
Here is how I solved it
foreach (Entity packingList in oPEntityCollection.Entities)
{
Entity newpackingList = new Entity()
{
LogicalName = packingList.LogicalName,
};
newpackingList.Attributes.AddRange(packingList.Attributes);
newpackingList.Attributes.Remove("primaryGuid");
Guid newOpGuid = orgService.Create(newpackingList);
tracingService.Trace($"OP record created sucessfully with guid {newOpGuid}");
}
So the Trick, issue was rather I was trying to assign packingList directly to newpackingList. This caused to assign packingList metadata attributes as well such. This was not acceptable with crm
But rather I should add it's attribute. This worked and created all child records.
Same worked for parent record as well
Entity parentEntity = orgService.Retrieve(context.PrimaryEntityName, context.PrimaryEntityId, new ColumnSet(true));
Entity newParentEntity = new Entity()
{
LogicalName = parentEntity.LogicalName,
};
newParentEntity.Attributes.AddRange(parentEntity.Attributes);
newParentEntity.Attributes.Remove("primaryGuid");
orgService.Create(newParentEntity);
If your question is "How do I duplicate an Entity retrieved from CRM?", your answer can be simplified.
var entity = orgService.Retrieve(context.PrimaryEntityName, context.PrimaryEntityId, new ColumnSet(true));
entity.Id = Guid.Empty;
entity.Attributes.Remove("primaryGuid");
orgService.Create(entity);

Update created record in Custom Workflow Activity -CRM -C#

I have created new entity.
From that entity i call Custom Workflow Activity entity that creates opportunity.
It works, but additionally I have to change some fields on created opportunity.
(I have to add opportunity products, and have to change price list for each opportunity).
As a test I tried to Update account field after creation, but it failed field. When i populate this account field before creation, it works, so it is not about that.
Here is the part of the code:
Entity entity = null;
if (context.InputParameters != null && context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
entity = (Entity)context.InputParameters["Target"];
}
else
{
entity = service.Retrieve(context.PrimaryEntityName, ((Guid)context.PrimaryEntityId), new ColumnSet(true));
}
Entity opportunity = new Entity("opportunity");
string name = entity.GetAttributeValue<string>("subject");
opportunity["name"] = name;
opportunityId = service.Create(opportunity);
EntityReference accountlookup = (EntityReference)entity.Attributes["ad_sendto"];
Guid accountId = accountlookup.Id;
opportunity["parentaccountid"] = new EntityReference("account", accountId);
service.Update(opportunity);
To repeat, it creates opportunity, but it doesn't work for update, is there any other way to do this, or do I have some errors here?
It fails because you are trying to update opportunity entity which does not have a primary key (opportunityid) set.
Instead of updating the opportunity after it was created, why not just assign the parentaccountid during the create operation?
var opportunity = new Entity("opportunity");
opportunity["name"] = entity.GetAttributeValue<string>("subject"); ;
opportunity["parentaccountid"] = entity.Attributes["ad_sendto"];
opportunityId = service.Create(opportunity);
For future references, if you ever have to update an entity that was just created or any entity for that matter:
var opportunityToUpdate = new Entity("opportunity")
{
Id = opportunityId
};
opportunityToUpdate["parentaccountid"] = entity.Attributes["ad_sendto"];
service.Update(opportunityToUpdate);

EntityState.Modified not working in Entity Code First

I Use this code for update one field in my table.( with Entity Framework 6.1.3)
var model = new MyTable { Id = Id, UpdateTime = DateTime.UtcNow };
var dbSet = this.dbContext.Set<MyTable>();
dbSet.Attach(model);
entry = this.dbContext.Entry(model);
entry.State = EntityState.Modified;
this.dbContext.SaveChanges();
but this not work and UpdateTime does not change.and when i change code to this:
var model = this.dbContext.Set<MyTable>().Find(id);
model = new MyTable { Id = Id, UpdateTime = DateTime.UtcNow };
var dbSet = this.dbContext.Set<MyTable>();
entry = this.dbContext.Entry(model);
entry.State = EntityState.Modified;
this.dbContext.SaveChanges();
I found that in my first code , EF look to UpdateTime field that did not change, but is this right when i write:
entry.State = EntityState.Modified;
ef must generate update code , then why it does not?
How must i do for solve this problem?
Finally i found what's the problem?
I have a required string field in my table , and i found that we need to fill reference type fileds in Entity framework , and it can not be empty or whitespace character but not required the right value, and in this state we must don't use
entry.State = EntityState.Modified;
and instead of it we must use
entry.Property("UpdateTime").IsModified = true;
therefore this problem can be solved by this way:
var model = new MyTable { Id = Id, UpdateTime = DateTime.UtcNow , Title = "EveryThing" };
var dbSet = this.dbContext.Set<MyTable>();
dbSet.Attach(model);
entry = this.dbContext.Entry(model);
entry.Property("UpdateTime").IsModified = true;
this.dbContext.SaveChanges();

How can I edit or add to a particular field without pull the all object

How I can do just this ( a.myFavorits.Add()) without pulling the all object to var a , because a has a lot of data, and I don't want to pull all a object, but I can't find a way do do it.
I want to do the lambada and the linq without return something but linq is always return something
public static void addFavorits(long f,long idUser)
{
using (var db = dataBase())
{
// here i pull object user from users table
var a = db.users.Where(c => c.id == idUser).SingleOrDefault();
// here i adding to the object field myFavorits new value
//myFavorits is also a table of entitys that connected to user object
a.myFavorits.Add(new BE.FavoritsUsersLong { myLong = f });
db.SaveChanges();
}
}
I thought to do something like this but i dont know how to set the field users_TableId that is the key that connect the 2 tables
public static void addFavorits(long favoritId,long idUser)
{
using (var db = dataBase())
{
db.favoritsUsersLong.Add(new BE.FavoritsUsersLong {myLong = favoritId}
/*,users_TableId =idUser*/);
db.SaveChanges();
}
}
Here's a concrete example that does what you want. In this example, only the Name of a Company is modified and saved. Or an item is added to one of its collections.
var cmp = new Company{ CmpId = 1, Name = "Cmp1" }; // CmpId is the primary key
db.Companies.Attach(cmp);
db.Entry(cmp).Property(c => c.Name).IsModified = true;
// Or add an entity to a collection:
cmp.Users = new[] {new User { Name = "a1", PassWord = "a1" } };
try
{
db.Configuration.ValidateOnSaveEnabled = false;
db.SaveChanges();
}
finally
{
db.Configuration.ValidateOnSaveEnabled = true;
}
Result in SQL:
DECLARE #0 VarChar(30) = 'Cmp1'
DECLARE #1 Int = 1
UPDATE [dbo].[Company]
SET [Name] = #0
WHERE ([CmpId] = #1)
There are a few things to note here:
Obviously you need to know the Id of the entity you want to modify.
The object you create is called a stub entity, which is an incomplete entity. When you try to save such an entity, EF is very likely to complain about null values in required properties. That's why almost certain you'd have to disable validation (temporarily, or, better, dispose the context immediately).
If you want to add an item to a collection, you should leave validation enabled, because you'd want to know for sure that the new entity is valid. So you shouldn't mix these two ways to use a stub entity.
If you often need roughly the same small part of your entity you may consider table splitting.
I'm guessing this is what you want? I don't see you 'editting' I only see you adding.
using (var db = dataBase())
{
var a = new user();
....
//set properties etc..
...
a.myFavorits.Add(new BE.FavoritsUsersLong { myLong = f });
db.users.Add(a);
db.SaveChanges();
}

Entity Framework 6 Add/Update - Error while edit and try to add edited entity as new one

I have a model like below
public class XYZModel
{
public string Id; // GUID, primary key;
public string Name;
public string AssociationId; // GUID, AllowNull;
}
what I am doing..
This is working fine
XYZModel abc = new XYZModel();
abc.Id = Convert.ToString(Guid.NewGuid());
abc.Name = "ABC Name";
xyzDbContext.XYZModels.Add(abc);
xyzDbContext.SaveChanges();
What is my goal ? Get entity by id, Edit it, Change its primary key Id value, and add it as a new entry. but error occurred while adding.
XYZModel xyz = xyzDbContext.XYZModels.Find("xyzguid");
//modifying it
xyz.AssociationId = xyz.Id;
xyz.Id = Convert.ToString(Guid.NewGuid());
xyz.Name = "New Name";
//trying to add it as new entry
xyzDbContext.XYZModels.Add(xyz);// Error
xyzDbContext.SaveChanges();
It throw an error
The property 'Id' is part of the object's key information and cannot be modified.
You can do that only if the xyz object is detached from Context.
Two ways to do that:
XYZModel xyz = xyzDbContext.XYZModels.Find("xyzguid");
xyzDbContext.Entry(xyz).State = EntityState.Detached;
Or using AsNoTracking.FirstOrDefault
XYZModel xyz = xyzDbContext.XYZModels.AsNoTracking().FirstOrDefault(s => s.Id =="xyzguid");
Your code with first approach:
XYZModel xyz = xyzDbContext.XYZModels.Find("xyzguid");
xyzDbContext.Entry(xyz).State = EntityState.Detached;
//modifying it
xyz.AssociationId = xyz.Id;
xyz.Id = Convert.ToString(Guid.NewGuid());
xyz.Name = "New Name";
//trying to add it as new entry
xyzDbContext.XYZModels.Add(xyz);// No Error
xyzDbContext.SaveChanges();
Note:
You must use DatabaseGeneratedOption.None annotation on Id property.
Entity Framework tracks objects as you edit them. If you want a new row inserted into the database, create a new object in memory with the values you want and add that. A library like AutoMapper might come in handy here.

Categories

Resources