The method that i used to delete an item from database is throwing back the error
"The object cannot be deleted because it was not found in the ObjectStateManager."
I followed multiple suggestions online to try to attach it but it was throwing back another error
"Attaching an entity of type 'databaseName' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate."
public bool deleteItem(Item s)
{
bool success = false;
using (DBEntities cxt = new DBEntities())
{
var saving = (from i in cxt.Items
where i.Id == s.Id
select i).FirstOrDefault();
cxt.Entry(s).State = System.Data.Entity.EntityState.Deleted;
//cxt.Items.Attach(s);
cxt.Items.Remove(s);
int delete = cxt.SaveChanges();
if (delete == 1)
{
success = true;
}
return success;
}
}
You can do this with one database call instead of 2. Attach the entity and then call Remove on the DbSet to delete it.
public bool deleteItem(Item s)
{
bool success = false;
using (DBEntities cxt = new DecagonDBEntities())
{
cxt.Items.Attach(s);
cxt.Items.Remove(s);
int delete = cxt.SaveChanges();
bool success = delete == 1;
return success;
}
}
If you still want to retrieve it for validation
public bool deleteItem(Item s)
{
bool success = false;
using (DBEntities cxt = new DecagonDBEntities())
{
var itemToDelete = cxt.Items.SingleOrDefault(_ => _.Id == s.Id);
// validate itemToDelete like check for null etc
cxt.Items.Remove(itemToDelete);
int delete = cxt.SaveChanges();
bool success = delete == 1;
return success;
}
}
Related
There is an update method throws exception but it works fine in first loging after second attempt throws exception with message;
**
Additional information: Attaching an entity of type
'Hsys.InfluenzaTaniBilgisi' failed because another entity of the same
type already has the same primary key value. This can happen when
using the 'Attach' method or setting the state of an entity to
'Unchanged' or 'Modified' if any entities in the graph have
conflicting key values. This may be because some entities are new and
have not yet received database-generated key values. In this case use
the 'Add' method or the 'Added' entity state to track the graph and
then set the state of non-new entities to 'Unchanged' or 'Modified' as
appropriate.
**
Iknow its common and found many smilar issue but I couldnt make it work..
here is code piece;
public void CreateUpdateInfluenzaTani(InfluenzaTaniBilgisi taniBilgisi)
{
using (HsysDbContext con = new HsysDbContext())
{
if (con.InfluenzaTestTanilari.Any(x => x.ICD10TaniKodu == taniBilgisi.ICD10Kodu && x.IsDeleted != true))
{
var taniExist = con.InfluenzaTaniBilgisi.FirstOrDefault(x => x.MuayeneId == taniBilgisi.MuayeneId && x.ICD10K
odu == taniBilgisi.ICD10Kodu && x.IsDeleted != true);
if (taniExist == null)
{
taniBilgisi.ObjectState = Framework.Entities.ObjectState.Added;
Create(taniBilgisi);
}
else
{
taniExist.HastaYasi = taniBilgisi.HastaYasi;
taniExist.HekimTC = taniBilgisi.HekimTC;
taniExist.ObjectState = Framework.Entities.ObjectState.Modified;
Update(taniExist);// throws Exception!
}
}
}
}
taniExist.ObjectState = Framework.Entities.ObjectState.Modified;
This is your issue.
You cannot use the Framework.Entities.ObjectState.Modified; on an existing key, entity frame work won't allow that.
You need to first do this:
taniExist.ObjectState = Framework.Entities.ObjectState.Added;
and then:
taniExist.ObjectState = Framework.Entities.ObjectState.Modified;
Your code will look like this:
taniExist.HastaYasi = taniBilgisi.HastaYasi;
taniExist.HekimTC = taniBilgisi.HekimTC;
taniExist.ObjectState = Framework.Entities.ObjectState.Added;
Update(taniExist);
Framework.Entities.ObjectState.Modified;
I wrote this code in controller:
public ActionResult AddNotice(NoticeViewModel nVN)
{
BOL.User CurrentUser = userbs.user.GetUser(User.Identity.Name);
int UserId = CurrentUser.ID;
var objNotice = new BOL.Notice()
{
NoticeID = nVN.SelectedNoticeTypeId,
ProductID = nVN.ProductID,
UserID = UserId
};
objBs.notice.AddNotice(objNotice);
methods:
public void AddNotice(Notice _notice)
{
int count = GetAllNotices().Where(x => x.UserID == _notice.UserID).Where(x => x.ProductID == _notice.ProductID).Count();
if (count == 0)
notice.InsertNotic(_notice);
else
notice.UpdateNotic(_notice);
}
public List<Notice> GetAllNotices()
{
return notice.GetAllNotices();
}
and :
public void UpdateNotic(Notice _notic)
{
db.Entry(_notic).State = EntityState.Modified;
db.Configuration.ValidateOnSaveEnabled = false;
db.SaveChanges();
db.Configuration.ValidateOnSaveEnabled = true;
}
when run update i get error in db.SaveChanges();
An exception of type 'System.Data.Entity.Infrastructure.DbUpdateConcurrencyException' occurred in EntityFramework.dll but was not handled in user code
Additional information: Store update, insert, or delete statement
affected an unexpected number of rows (0). Entities may have been
modified or deleted since entities were loaded
and i don't know what is problem??
In your AddNotice in the update case the Notice instance wasn't obtained from the same context that you are using to update it.
Change tracking depends on the entity being associated with the context and then updated.
Or you can use IDbSet<T>.Attach(entity) to associate an instance created elsewhere.
I have an MVC application with the following code in the POST method of the controller. I am doing an EF Add and obviously that is not right. I want it to add the record if it doesn't exist, otherwise Update. How can I do that please?
try
{
AttributeEntities db = new AttributeEntities();
IEnumerable<string> items = viewModel.SelectedAttributes2;
int i = 0;
foreach (var item in items)
{
var temp = item;
// Save it
SelectedHarmonyAttribute attribute = new SelectedHarmonyAttribute();
attribute.CustomLabel = viewModel.ItemCaptionText;
attribute.IsVisible = viewModel.Isselected;
string harmonyAttributeID = item.Substring(1, 1);
// attribute.OrderNumber = Convert.ToInt32(order);
attribute.OrderNumber = i++;
attribute.HarmonyAttribute_ID = Convert.ToInt32(harmonyAttributeID);
db.SelectedHarmonyAttributes.Add(attribute);
db.SaveChanges();
}
}
You would need to check the database for the record you are trying to add/update. If the look-up returns null, that means that it doesn't exist in the database. If it does, you can modify the record that you looked up and call db.SaveChanges() to persist the changes you made to the database.
Edit:
int id = Convert.ToInt32(harmonyAttributeID);
var existingEntry = db.SelectedHarmonyAttributes.SingleOrDefault(x => x.HarmonyAttribute_ID == id);
One common way to determine an add or update is by simply looking at an identifier field, and setting the appropriate state.
using System.Data;
SelectedHarmonyAttribute attribute;
using (var db = new YourDbContext())
{
db.Entry(attribute).State = attribute.HarmonyAttribute_ID == 0 ? EntityState.Added : EntityState.Modified;
db.SaveChanges();
}
You could import the System.Data.Entity.Migrations namespace and use the AddOrUpdate extension method:
db.SelectedHarmonyAttributes.AddOrUpdate(attribute);
db.SaveChanges();
EDIT:
I'm assuming that SelectedHarmonyAttributes is of type DbSet
EDIT2:
Only drawback with doing it this way (and it may not be a concern for you), is that your entity isn't responsible for it's own state change. This means that you can update any property of the entity to something invalid, where you might want to internally validate it on the entity itself or maybe do some other processing you always want to occur on update. If these things are a concern for you, you should add a public Update method onto the entity and check for its existence on the database first. e.g:
var attribute = db.SelectedHarmonyAttributes.SingleOrDefault(x => x.HarmonyAttribute_ID == harmonyAttributeID);
if (attribute != null)
{
attribute.Update(viewModel.ItemCaptionText, viewModel.Isselected, i++);
}
else
{
attribute = new Attribute(viewModel.ItemCaptionText, viewModel.Isselected);
db.SelectedHarmonyAttributes.Add(attribute);
}
db.SaveChanges();
Your update method might look something like:
public void Update(string customLabel, bool isVisible, int orderNumber)
{
if (!MyValidationMethod())
{
throw new MyCustomException();
}
CustomLabel = customLabel;
IsVisible = isVisible;
OrderNumber = orderNumber;
PerformMyAdditionalProcessingThatIAlwaysWantToHappen();
}
Then make all of the entities' properties public "get" but protected "set" so they can't be updated from outside the entity itself. This might be going off an a bit of a tangent but using the AddOrUpdate method would assume you don't want to control the way an update occurs and protect your domain entity from getting into an invalid state etc. Hope this helps!
I have a problem with entity framework code first six working so disconnected. The problem occurs when I want to mark an entity as modified, the entity has association properties loaded with a new instance of DbContext, to be more precise the source of my hit and then get the save.
public List<Venta> Get(Expression<Func<Venta, bool>> predicate)
{
try
{
int num = 0;
List<Venta> ventas = new List<Venta>();
using (_context = new MyContext(MyContext.GetConnectionString()))
{
if (predicate == null)
ventas = _context.Ventas.Include("Mesa").Include("Usuario").Include("Pago").ToList();
else
ventas = _context.Ventas.Include("Mesa").Include("Usuario").Include("Pago").Where(predicate).ToList();
}
//I use the other repo to load related entities
UsuarioRepository userRepo = new UsuarioRepository();
foreach (Venta item in ventas)
{
item.GetType().GetProperty("Usuario").SetValue(item, userRepo.Get(u => u.Id == item.UsuarioId).First(), null);
}
//I use the other repo to load related entities
ProductoRepository prodRepo = new ProductoRepository();
foreach (VentaProducto item in ventas.SelectMany(vta => vta.Detalle).ToList())
{
Producto p = prodRepo.Get(prod => item.ProductoId == prod.Id).First();
item.GetType().GetProperty("Producto").SetValue(item, p, null);
}
ventas.ForEach(vta => vta.State = DomainEntityState.Unchanged);
return ventas;
}
catch (Exception ex)
{
throw new Exception("Error al traer las Ventas", ex);
}
}
public override int Save(Venta venta)
{
int saves = 0;
EntityState state;
EntityState stateProducto;
//New Instance of the context without entities in the DbSet's
using (MyContext context = new MyContext(MyContext.GetConnectionString()))
{
try
{
if (venta.IsNewEntity) //Venta nueva
{
state = EntityState.Added;
stateProducto = EntityState.Modified;
}
else
{
state = EntityState.Modified;
stateProducto = EntityState.Modified;
}
//int usuarios = context.Usuarios.Local.Count; //I get 0
//int productos = context.Productos.Local.Count; //I get 0
//int ventasProductos = context.VentasProducto.Local.Count; // I get 0
venta.Usuario = null;
if (venta.Pago != null)
venta.Pago.Usuario = null;
if (venta.Pago != null)
{
EntityState estadoPago = context.GetEntityState(venta.Pago);
}
//HERE IS THE PROBLEM
context.SetEntityState(venta, state);
saves = context.SaveChanges();
}
catch (Exception ex)
{
throw new Exception("Error al grabar la venta", ex);
}
}
return saves;
}
Finally I get the following error ....
Attaching an entity of type 'Jackie.Domain.Entities.Usuario' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.
The most strange is that if I load all entities with the same instance of context does not have that problem. It will be a bug? No longer think of anything more. Thank you all. Made with google translator.
There are (at least) two Usuario properties in the object graph - venta.Usuario and venta.Pago.Usuario. By attaching the venta entity, the entity objects in these two Usuario properties will be attached as Unmodified. If these two properties hold two different instances of the Usuario class with the same PK value, when the second is attached it will throw the error you received. This seems quite possible as you're loading navigation properties via different instances of the context with some eager loading thrown into the mix.
Break at the call to context.SetEntityState(venta, state) and see if those two Usuario objects are actually the same instance or two different instances with the same PK value(s).
Ok, I am attempting to use this custom extension to perform an entity update. Right now it should update all properties and then all of its related ends (references). The problem is even though the entity with changes does have a related end with an entity key that is valid and correct (verified in the debugger its there). When the RelationshipManager gets it they key is null.. Anyone see anything wrong with this code?
public static void ApplyChanges(this ObjectContext context, EntityObject entityWithChanges)
{
if (entityWithChanges.EntityState == EntityState.Detached)
{
object entityCurrentlyInDB = null;
if (context.TryGetObjectByKey(entityWithChanges.EntityKey, out entityCurrentlyInDB))
{
context.ApplyPropertyChanges(entityWithChanges.EntityKey.EntitySetName, entityWithChanges);
foreach (var relatedEnd in ((IEntityWithRelationships)entityCurrentlyInDB).RelationshipManager.GetAllRelatedEnds())
{
var oldRef = relatedEnd as EntityReference;
if (oldRef != null)
{
var newRef =
((IEntityWithRelationships)entityWithChanges).RelationshipManager
.GetRelatedEnd(oldRef.RelationshipName, oldRef.TargetRoleName) as EntityReference;
oldRef.EntityKey = newRef.EntityKey;
}
}
}
else
{
throw new ObjectNotFoundException();
}
}
}
This is just a modified version of what I found
Here
Appreciate the help.
UPDATE:
This is the Update Method
public static void UpdateTemplate(Template template)
{
using (TheEntities context = new TheEntities())
{
context.ApplyChanges(template);
try
{
context.SaveChanges();
}
catch (OptimisticConcurrencyException)
{
context.Refresh(RefreshMode.ClientWins, template);
context.SaveChanges();
}
context.RemoveTracking(template);
}
}
This is the unit test:
[TestMethod]
public void CanUpdateATemplate()
{
Template template = new Template();
template.Name = "Test";
template.Description = "Test";
TemplateType type = TemplateManager.FindTemplateTypeByName("Test");
if (type == null)
{
type = new TemplateType();
type.Name = "Test";
}
template.TemplateType = type;
TemplateManager.AddTemplate(template);
template = TemplateManager.FindTemplateByID(template.TemplateID);
Assert.IsNotNull(template);
type = TemplateManager.FindTemplateTypeByName("Round");
if (type == null)
{
type = new TemplateType();
type.Name = "Round";
}
template.TemplateType = type;
TemplateManager.UpdateTemplate(template);
template = TemplateManager.FindTemplateByID(template.TemplateID);
Assert.IsNotNull(template);
Assert.IsTrue(template.TemplateType.Name == "Round");
TemplateManager.DeleteTemplate(template);
template = TemplateManager.FindTemplateByID(template.TemplateID);
Assert.IsNull(template);
}
This is simply not possible due to the way Detach works in EF.
I found that if I added key information myself I could get the generic call to work and even save it.
The problem is that the moment you go to return an entity after calling Detach on it you lose all relationship data. Ive found some write ups on writing graph managers for each entity but I find that a waste seeing as EF should do this stuff (supposedly it will in v2).
EF simply is not ready for N-Tier deployments.