Cannot get GET: api/xyz to work with Entity Framework - c#

I have a table a with a foreign key to another table b. The EF model was generated from the database. What I want is just all the data from the table a.
But the auto-generated method
// GET: api/Massnahmentyp
public IQueryable<MASSNAHMENTYP> GetMASSNAHMENTYPs()
{
return db.MASSNAHMENTYPs;
}
returns nothing. However, the method
// GET: api/Massnahmentyp/5
[ResponseType(typeof(MASSNAHMENTYP))]
public IHttpActionResult GetMASSNAHMENTYP(decimal id)
{
MASSNAHMENTYP mASSNAHMENTYP = db.MASSNAHMENTYPs.Find(id);
if (mASSNAHMENTYP == null)
{
return NotFound();
}
return Ok(mASSNAHMENTYP);
}
works and returns the correct entry. What do I do wrong?
Update
Ok, it seems that it worked all the time, just the response was way to big because of the foreign key. Is it possible to ignore the dependencies, so that it does not join thousands of entries into the response? Table a has only 6 entries and I only want them.

What about following code?
// GET: api/Massnahmentyp
[HttpGet]
public IEnumerable<MASSNAHMENTYP> GetMASSNAHMENTYPs()
{
return db.MASSNAHMENTYPs.ToList();
}
I think you should annotate your method with [HttpGet].
Update: For the new part of your question:
You can disable lazy loading in DbContext:
public class YourContext : DbContext
{
public YourContext()
{
this.Configuration.LazyLoadingEnabled = false;
}
}

Related

Override DbSet.Remove() or Restore Entity values within DbContext ChangeTracker.DetectChanges()

The current issue that I am facing is that I am implementing a Soft Delete on all objects, but .Remove() on an Entity will remove foreign keys during it's process.
MyObject (ie):
Id = 1
Name = Blah
PageID = null (was 10 before .Remove() was called, I want to preserve this during SoftDelete)
Is is possible to override public virtual TEntity Remove(TEntity entity)? or modify my ChangeTracker.DetectChanges(); section?
Like I briefly mentioned, I am using ChangeTracker.DetectChanges(); to set the Entity (ObjectStateEntry) back to Modified (entry.ChangeState(EntityState.Modified);) and setting another Property IsActive to false, however the "stripping" of other fields has already been done when .Remove() was called.
MVC creates Controllers for all my objects and within the DeleteConfirm is db.entityObject.Remove(entity).
... or is there a different approach I should be looking into?
I can provide more details, please let me know what you may need.
Example within a Controller:
// POST: MyObject/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(Guid id)
{
MyObject myObject = db.MyObject.Find(id);
db.MyObject.Remove(myObject);
db.SaveChanges();
return RedirectToAction("Index");
}
Subset of my DbContext code:
public class AppDbContext : DbContext
{
public override int SaveChanges()
{
ChangeTracker.DetectChanges();
objectContext.ObjectStateManager.GetObjectStateEntries(
EntityState.Added |
EntityState.Modified |
EntityState.Deleted);
foreach (ObjectStateEntry entry in objectStateEntryList)
{
if (!entry.IsRelationship)
{
switch (entry.State)
{
case EntityState.Deleted:
entry.ChangeState(EntityState.Modified);
((BaseObject)entry.Entity).IsActive = false;
//Update #1
this.Entry(entry.Entity).Reload();
//Is is possible to "restore" the original object?
//or override .Remove()?
break;
}
}
}
return base.SaveChanges();
}
}
Thank you in advance.
Update 1:
Is it as simple as calling the following?
this.Entry(entry.Entity).Reload();
I think this worked, I understand this might be another database call, but resolves for now. Further testing needed.
Let me suggest to #Derek the:
Update 2:
public class AppDbContext : DbContext
{
public override int SaveChanges()
{
ChangeTracker.DetectChanges();
objectContext.ObjectStateManager.GetObjectStateEntries(
EntityState.Added |
EntityState.Modified |
EntityState.Deleted);
foreach (ObjectStateEntry entry in objectStateEntryList)
{
if (!entry.IsRelationship)
{
switch (entry.State)
{
case EntityState.Deleted:
// Update #2
// ---------
// Set the state to 'Unchanged'.
// Only updated fields will be sent to the Db.
entry.ChangeState(EntityState.Unchanged);
((BaseObject)entry.Entity).IsActive = false;
break;
}
}
}
return base.SaveChanges();
}
}
Thanks to Entity Framework Core: Soft Delete blog post from Ryan Southgate.

Entity Framework and MVC: generating CONTROLLER code from entities

I'm on an assignment to to expose SQL data using MVC via OData.
I'm working with an existing project, Visual Studio 2015.
A bunch of tables have already been exposed.
Please first accept my apologies for perhaps a poorly crafted post.
I'm having a hard time figuring out what I'm actually working with.
In addition, I've had only a day to familiarize myself with this project.
I know that I said MVC but as far as I can tell, this project does not have VIEWS. I do believe however that the consumers of this project will read JSON.
I've used the Entity Framework to build the MODEL for the additional tables required to finish my assignment.
I'm working now on the CONTROLLER code, and I'd like to use a tool to automate that portion as much as possible. Below please find an example of a CONTROLLER already defined. I include that to help you get a feel for the type of tool I'm looking for.
Does such a tool exist? Or do I have to notepad a CONTROLLER for the tables that I've added to the project?
Thank you kindly for reading my post and for any assistance you can offer :)
public class BlockController : ODataController
{
AccordNewModel _db = new AccordNewModel();
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
public IHttpActionResult Get()
{
return Ok(_db.Block.AsQueryable());
}
[ODataRoute()]
[HttpPost]
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
public IHttpActionResult Post(Block newBlock)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_db.Block.Add(newBlock);
_db.SaveChanges();
return Created(newBlock);
}
[ODataRoute()]
[HttpPut]
[EnableQuery(AllowedQueryOptions = AllowedQueryOptions.All)]
public IHttpActionResult Put(Block block)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
_db.Block.AddOrUpdate(p => new { p.BlockID }, block);
_db.SaveChanges();
return Updated(block);
}
[HttpDelete]
public IHttpActionResult Delete([FromODataUri] int key)
{
var block = _db.Block.SingleOrDefault(t => t.BlockID == key);
_db.Block.Remove(block);
_db.SaveChanges();
return Content(HttpStatusCode.NoContent, "Deleted");
}
protected override void Dispose(bool disposing)
{
_db.Dispose();
base.Dispose(disposing);
}
}
It makes little sense to write very similar controller code multiple times, I would advise against generating 1 controller per entity. Instead you could use a generic solution:
public class BaseController<T> : ODataController
{
AccordNewModel _db = new AccordNewModel();
[EnableQuery]
public IHttpActionResult Get()
{
return Ok(_db.Set<T>().AsQueryable());
}
[HttpPost]
public IHttpActionResult Post(T posted)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var added = _db.Set<T>().Add(posted);
_db.SaveChanges();
return Created(added);
}
//Etc... Write generic controller methods using Db.Set<T>()
Then for every entity you need not do much, here is how your 'block' entity controller would look:
public class BlockController : BaseController<Block> { }
For delete and update you need some way to identify the generic object of T by Id (int key). I know of two ways to do this:
1: Let your entities implement an interface IHasId which ensures they have an int Id property, then add a generic constraint to the BaseController class like so: public class BaseController<T> : ODataController where T : IHasId. Delete method could look like this:
[HttpDelete]
public IHttpActionResult Delete([FromODataUri] int key)
{
var found = _db.Set<T>().FirstOrDefault(e => e.Id == key);
if(found != null)
{
_db.Set<T>().Remove(found);
_db.SaveChanges();
return StatusCode(System.Net.HttpStatusCode.NoContent);
}
else
{
return NotFound();
}
}
Or, 2: Make the BaseController class abstract and add: protected abstract T GetById(int id);. Then inheriting classes (such as 'BlockController') must implement a method to get the object from the Db by id. You will have to implement this method for every entity, this is still less work than writing individual controllers for every entity. The delete method would look almost the same as the one above except: var found = GetById(key);.
I use Delete as an example, but if you have some way to get an entity by id you can quite easily implement the Post and possibly a Get(int key) as well.
With this generic base class the code per entity is minimal and writing it for every entity shouldn't be too much work.

Custom value type, EF Code First and routing

In our WebApi project we use EF CodeFirst approach. Also we use 2 types of databases: SQL Server and MySQL. All tables have the field ID, but in SQL Server database this field has int data type, in MySQL database this field is char(36) and contains GUID.
To solve the problem I created a custom value type like IdType and changed all model classes to use that type insted int:
public class Document
{
public IdType ID { get; set; }
public string DocumentNm { get; set; }
...
}
Then I configured the DbContext (e.g for SQL Server)
modelBuilder.Properties<IdType>().Configure(c => c.HasColumnType("int"));
...and changed repository:
public interface IRepository<T> where T : IEntity
{
IQueryable<T> GetAll();
T GetById(IdType id);
...
}
After that, when I try to go to e.g. http://localhost:7081/api/Document, it gives me an error:
Multiple actions were found that match the request: \r\nGet on type
WebUI.Controllers.API.DocumentController\r\nGetById on type
WebUI.Controllers.API.DocumentController
I use default settings of routing. Here is [HttpGet] methods from DocumentController:
public HttpResponseMessage Get() { ... }
public HttpResponseMessage GetById(IdType id) { ... }
How can I solve the problem? Could this be the cause of incorrect implementation of IdType?
P.S. I created IdType for int values as described here. if I have to add more informations, please let me know.
UPDATE
DocumentController:
public HttpResponseMessage GetById(IdType id)
{
var entity = repository.GetById(id);
if (entity == null)
{
return ErrorMsg(HttpStatusCode.NotFound, string.Format("No {0} with ID = {1}", GenericTypeName, id););
}
return Request.CreateResponse(HttpStatusCode.OK, entity);
}
My repository:
public virtual T GetById(IdType id)
{
return GetAll().FirstOrDefault(x => x.ID == id);
}
public virtual IQueryable<T> GetAll()
{
return entities = context.Set<T>();
}
It seems that it not implemented yet in current version of Entity Framework
And as mentioned in task on GitHub
we're currently planning to work on lighting this feature up after our
initial RTM of EF7.

How to manually set entity primary key in Entity Framework code first database?

Well, I have the following model structure: I have one class - DatabaseEntity which is basically
public class DatabaseEntity
{
public int Id { get; set; }
}
so each entity like product, category etc will inherit DatabaseEntity and have Id property. Also I have typical EntityFramework repository class with InsertOrUpdate method:
private readonly DbContext _database;
public void InsertOrUpdate<TObject>(TObject entity) where TObject : DatabaseEntity
{
if(entity.Id == default(int))
{
// New entity
DbSet<TObject>().Add(entity);
}
else
{
// Existing entity
_database.Entry(entity).State = EntityState.Modified;
}
_database.SaveChanges();
}
Then I download from eBay via eBay api list of categoies I have to add to database. Basically category is:
public class EbayCategory : DatabaseEntity
{
// It has Id since it inherits DatabaseEntity
public string Name { get; set; }
// ... some other properties
}
But, the problem is, when I download those categories I download and their Id properties, which, of course, already have values. And when I try to save them to database like:
public void UpdateCategories(IEnumerable<EbayCategory> newCategories)
{
foreach (var newCategory in newCategories)
{
_repository.InsertOrUpdate(newCategory);
}
}
I face some issues... First of all, entity.Id != default(int) because it has value, so repository tries to update this entity, instead of adding, but it is not in the database or context so it throws the following exception:
System.Data.Entity.Infrastructure.DbUpdateConcurencyException
"Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries."
... because it thinks that someone else deleted entity which I am trying to update. How can I save this InsertOrUpdate logic, since a lot of projects are based on it, and be able to add items (EbayCategories) with primary key (Id) to database and then update/delete them like other entities without discarding EbayCategory.Id value?
To allow you to manually generate Ids you need a class that has a manually generated ID - so it cannot inherit from DatabaseEntity
public class EbayCategory
{
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
public string Name { get; set; }
// ... some other properties
}
Now you will need a different InsertOrUpdate to handle entities that have manually generated keys:
public void InsertOrUpdate(EbayCategory entity)
{
if(Find(entity.ID == null)
{
// New entity
DbSet<EbayCategory>().Add(entity);
}
else
{
// Existing entity
_database.Entry(entity).State = EntityState.Modified;
}
_database.SaveChanges();
}
Colin's answer above quite correctly shows how to achieve this setting using data annotations.
But in the presented problem the entity is a subclass so you can't add the annotation without changing the entity class.
There is an alternative configuration method: Fluent Configuration. Here's my example using an EntityTypeConfiguration class:
public class LookupSchoolsConfiguration : EntityTypeConfiguration<LookupSchools>
{
public LookupSchoolsConfiguration()
{
Property(l => l.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
}
}
You can also add configuration directly to the modelBuilder as per this post: https://stackoverflow.com/a/4999894/486028

ASP.NET MVC - Attaching an entity of type 'MODELNAME' failed because another entity of the same type already has the same primary key value

In a nutshell the exception is thrown during POSTing wrapper model and changing the state of one entry to 'Modified'. Before changing the state, the state is set to 'Detached' but calling Attach() does throw the same error. I'm using EF6.
Please find my code below(model names have been changed to make it easier to read)
Model
// Wrapper classes
public class AViewModel
{
public A a { get; set; }
public List<B> b { get; set; }
public C c { get; set; }
}
Controller
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
if (!canUserAccessA(id.Value))
return new HttpStatusCodeResult(HttpStatusCode.Forbidden);
var aViewModel = new AViewModel();
aViewModel.A = db.As.Find(id);
if (aViewModel.Receipt == null)
{
return HttpNotFound();
}
aViewModel.b = db.Bs.Where(x => x.aID == id.Value).ToList();
aViewModel.Vendor = db.Cs.Where(x => x.cID == aViewModel.a.cID).FirstOrDefault();
return View(aViewModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(AViewModel aViewModel)
{
if (!canUserAccessA(aViewModel.a.aID) || aViewModel.a.UserID != WebSecurity.GetUserId(User.Identity.Name))
return new HttpStatusCodeResult(HttpStatusCode.Forbidden);
if (ModelState.IsValid)
{
db.Entry(aViewModel.a).State = EntityState.Modified; //THIS IS WHERE THE ERROR IS BEING THROWN
db.SaveChanges();
return RedirectToAction("Index");
}
return View(aViewModel);
}
As shown above line
db.Entry(aViewModel.a).State = EntityState.Modified;
throws exception:
Attaching an entity of type 'A' 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.
Does anybody see anything wrong in my code or understand in what circumstances it would throw such error during editing a model?
Problem SOLVED!
Attach method could potentially help somebody but it wouldn't help in this situation as the document was already being tracked while being loaded in Edit GET controller function. Attach would throw exactly the same error.
The issue I encounter here was caused by function canUserAccessA() which loads the A entity before updating the state of object a. This was screwing up the tracked entity and it was changing state of a object to Detached.
The solution was to amend canUserAccessA() so that the object I was loading wouldn't be tracked. Function AsNoTracking() should be called while querying the context.
// User -> Receipt validation
private bool canUserAccessA(int aID)
{
int userID = WebSecurity.GetUserId(User.Identity.Name);
int aFound = db.Model.AsNoTracking().Where(x => x.aID == aID && x.UserID==userID).Count();
return (aFound > 0); //if aFound > 0, then return true, else return false.
}
For some reason I couldnt use .Find(aID) with AsNoTracking() but it doesn't really matter as I could achieve the same by changing the query.
Hope this will help anybody with similar problem!
Interestingly:
_dbContext.Set<T>().AddOrUpdate(entityToBeUpdatedWithId);
Or if you still is not generic:
_dbContext.Set<UserEntity>().AddOrUpdate(entityToBeUpdatedWithId);
seems to solved my problem smoothly.
It seems that entity you are trying to modify is not being tracked correctly and therefore is not recognized as edited, but added instead.
Instead of directly setting state, try to do the following:
//db.Entry(aViewModel.a).State = EntityState.Modified;
db.As.Attach(aViewModel.a);
db.SaveChanges();
Also, I would like to warn you that your code contains potential security vulnerability. If you are using entity directly in your view model, then you risk that somebody could modify contents of entity by adding correctly named fields in submitted form. For example, if user added input box with name "A.FirstName" and the entity contained such field, then the value would be bound to viewmodel and saved to database even if the user would not be allowed to change that in normal operation of application.
Update:
To get over security vulnerability mentioned previously, you should never expose your domain model as your viewmodel but use separate viewmodel instead. Then your action would receive viewmodel which you could map back to domain model using some mapping tool like AutoMapper. This would keep you safe from user modifying sensitive data.
Here is extended explanation:
http://www.stevefenton.co.uk/Content/Blog/Date/201303/Blog/Why-You-Never-Expose-Your-Domain-Model-As-Your-MVC-Model/
Try this:
var local = yourDbContext.Set<YourModel>()
.Local
.FirstOrDefault(f => f.Id == yourModel.Id);
if (local != null)
{
yourDbContext.Entry(local).State = EntityState.Detached;
}
yourDbContext.Entry(applicationModel).State = EntityState.Modified;
for me the local copy was the source of the problem.
this solved it
var local = context.Set<Contact>().Local.FirstOrDefault(c => c.ContactId == contact.ContactId);
if (local != null)
{
context.Entry(local).State = EntityState.Detached;
}
My case was that I did not have direct access to EF context from my MVC app.
So if you are using some kind of repository for entity persistence it could be appropiate to simply detach explicitly loaded entity and then set binded EntityState to Modified.
Sample (abstract) code:
MVC
public ActionResult(A a)
{
A aa = repo.Find(...);
// some logic
repo.Detach(aa);
repo.Update(a);
}
Repository
void Update(A a)
{
context.Entry(a).EntityState = EntityState.Modified;
context.SaveChanges();
}
void Detach(A a)
{
context.Entry(a).EntityState = EntityState.Detached;
}
Use AsNoTracking() where you are getting your query.
var result = dbcontext.YourModel.AsNoTracking().Where(x => x.aID == aID && x.UserID==userID).Count();
I have added this answer only because the problem is explained based on more complex data pattern and I found it hard to understand here.
I created a fairly simple application. This error occurred inside Edit POST action. The action accepted ViewModel as an input parameter. The reason for using the ViewModel was to make some calculation before the record was saved.
Once the action passed through validation such as if(ModelState.IsValid), my wrongdoing was to project values from ViewModel into a completely new instance of Entity. I thought I'd have to create a new instance to store updated data and then saved such instance.
What I had realised later was that I had to read the record from database:
Student student = db.Students.Find(s => s.StudentID == ViewModel.StudentID);
and updated this object. Everything works now.
I thought I'd share my experience on this one, even though I feel a bit silly for not realising sooner.
I am using the repository pattern with the repo instances injected into my controllers. The concrete repositories instantiate my ModelContext (DbContext) which lasts the lifetime of the repository, which is IDisposable and disposed by the controller.
The issue for me was that I have a modified stamp and row version on my entities, so I was getting them first in order to compare with the inbound headers. Of course, this loaded and tracked the entity that was subsequently being updated.
The fix was simply to change the repository from newing-up a context once in the constructor to having the following methods:
private DbContext GetDbContext()
{
return this.GetDbContext(false);
}
protected virtual DbContext GetDbContext(bool canUseCachedContext)
{
if (_dbContext != null)
{
if (canUseCachedContext)
{
return _dbContext;
}
else
{
_dbContext.Dispose();
}
}
_dbContext = new ModelContext();
return _dbContext;
}
#region IDisposable Members
public void Dispose()
{
this.Dispose(true);
}
protected virtual void Dispose(bool isDisposing)
{
if (!_isDisposed)
{
if (isDisposing)
{
// Clear down managed resources.
if (_dbContext != null)
_dbContext.Dispose();
}
_isDisposed = true;
}
}
#endregion
This allows the repository methods to re-new their context instance upon each use by calling GetDbContext, or use a previous instance if they so desire by specifying true.
I had this problem with local var and i just detach it like this:
if (ModelState.IsValid)
{
var old = db.Channel.Find(channel.Id);
if (Request.Files.Count > 0)
{
HttpPostedFileBase objFiles = Request.Files[0];
using (var binaryReader = new BinaryReader(objFiles.InputStream))
{
channel.GateImage = binaryReader.ReadBytes(objFiles.ContentLength);
}
}
else
channel.GateImage = old.GateImage;
var cat = db.Category.Find(CatID);
if (cat != null)
channel.Category = cat;
db.Entry(old).State = EntityState.Detached; // just added this line
db.Entry(channel).State = EntityState.Modified;
await db.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(channel);
Problem causes of loaded objects with same Key, so first we will detach that object and do the the updating to avoid conflict between two object with the same Key
i mange to fix the issue by updating state. when you trigger find or any other query operation on the same record sate has been updated with modified so we need to set status to Detached then you can fire your update change
ActivityEntity activity = new ActivityEntity();
activity.name="vv";
activity.ID = 22 ; //sample id
var savedActivity = context.Activities.Find(22);
if (savedActivity!=null)
{
context.Entry(savedActivity).State = EntityState.Detached;
context.SaveChanges();
activity.age= savedActivity.age;
activity.marks= savedActivity.marks;
context.Entry(activity).State = EntityState.Modified;
context.SaveChanges();
return activity.ID;
}
I had a similar issue, after probing for 2-3 days found ".AsNoTracking" should be removed as EF doesn't track the changes and assumes there are no changes unless an object is attached. Also if we don't use .AsNoTracking, EF automatically knows which object to save/update so there is no need to use Attach/Added.
I encountered this error where
two methods, A & B, in a single controller both used the same instance of an ApplicationDbContext, and
method A called method B
private ApplicationDbContext db;
// api methods
public JsonResult methodA(string id){
Resource resource = db.Resources.Find(id);
db.Entry(resource).State = EntityState.Modified;
db.SaveChanges();
return methodB()
}
public JsonResult methodB(string id){
Resource resource = db.Resources.Find(id);
db.Entry(resource).State = EntityState.Modified;
db.SaveChanges();
return new JsonResult();
}
I changed method B to have a using statement and rely only on the local db2.
After:
private ApplicationDbContext db;
// api methods
public JsonResult methodA(string id){
Resource resource = db.Resources.Find(id);
db.Entry(resource).State = EntityState.Modified;
db.SaveChanges();
return methodB()
}
public JsonResult methodB(string id){
using (var db2 = new ApplicationDbContext())
{
Resource resource = db2.Resources.Find(id);
db2.Entry(resource).State = EntityState.Modified;
db2.SaveChanges();
}
return new JsonResult();
}
Similar to what Luke Puplett is saying, the problem can be caused by not properly disposing or creating your context.
In my case, I had a class which accepted a context called ContextService:
public class ContextService : IDisposable
{
private Context _context;
public void Dispose()
{
_context.Dispose();
}
public ContextService(Context context)
{
_context = context;
}
//... do stuff with the context
My context service had a function which updates an entity using an instantiated entity object:
public void UpdateEntity(MyEntity myEntity, ICollection<int> ids)
{
var item = _context.Entry(myEntity);
item.State = EntityState.Modified;
item.Collection(x => x.RelatedEntities).Load();
myEntity.RelatedEntities.Clear();
foreach (var id in ids)
{
myEntity.RelatedEntities.Add(_context.RelatedEntities.Find(id));
}
_context.SaveChanges();
}
All of this was fine, my controller where I initialized the service was the problem. My controller originally looked like this:
private static NotificationService _service =
new NotificationService(new NotificationContext());
public void Dispose()
{
}
I changed it to this and the error went away:
private static NotificationService _service;
public TemplateController()
{
_service = new NotificationService(new NotificationContext());
}
public void Dispose()
{
_service.Dispose();
}
Here what I did in the similar case.
That sitatuation means that same entity has already been existed in the context.So following can help
First check from ChangeTracker if the entity is in the context
var trackedEntries=GetContext().ChangeTracker.Entries<YourEntityType>().ToList();
var isAlreadyTracked =
trackedEntries.Any(trackedItem => trackedItem.Entity.Id ==myEntityToSave.Id);
If it exists
if (isAlreadyTracked)
{
myEntityToSave= trackedEntries.First(trackedItem => trackedItem.Entity.Id == myEntityToSave.Id).Entity;
}
else
{
//Attach or Modify depending on your needs
}
I solve this problem with a "using" block
using (SqlConnection conn = new SqlConnection(connectionString))
{
// stuff to do with data base
}
// or if you are using entity framework
using (DataBaseEntity data = new DataBaseEntity)
{
}
Here is where I get the idea https://social.msdn.microsoft.com/Forums/sqlserver/es-ES/b4b350ba-b0d5-464d-8656-8c117d55b2af/problema-al-modificar-en-entity-framework?forum=vcses is in spanish (look for the second answer)
you can use added method like;
_dbContext.Entry(modelclassname).State = EntityState.Added;
but in many case if you want to use more than one model at that time this won't work because entity is already attached to another entity. So, at that time you can use ADDOrUpdate Entity Migration method which simply migrates object from one to another and as a result you wouldn't get any error.
_dbContext.Set<modelclassname>().AddOrUpdate(yourmodel);
Clear all State
dbContextGlobalERP.ChangeTracker.Entries().Where(e => e.Entity != null).ToList().ForEach(e => e.State = EntityState.Detached);
Reasons I've encountered this error:
Did not use .AsNoTracking() when querying for existing entities. Especially when calling a helper function to check permissions.
Calling .Include() on a query and then trying to edit the parent. Example: var ent = repo.Query<Ent>().Include(e=>e.Ent2).First(); ...repo.Edit(e.Ent2); repo.Edit(e); If I'm going to edit a nested object, I try to separate these into separate query calls now. If you can't do that, set the child object to null and iterate through lists, detaching objects like this
Editing an old entity in a Put web call. The new item is already added to the repo, so modify that one and have it be saved in super.Put(). Example of what will throw an error: public void Put(key, newItem){ var old = repo.Query<Entity>().Where(e=>Id==key).First(); ... repo.Edit(old); super.Put(key,newItem); ... }
Multiple helper functions edit the same entity. Instead of passing the ID as a parameter into each function, pass a reference to the entity. Error solved!
In my case , I had wrote really two times an entity of same type . So I delete it and all things work correctly
This problem may also be seen during ViewModel to EntityModel mapping (by using AutoMapper, etc.) and trying to include context.Entry().State and context.SaveChanges() such a using block as shown below would solve the problem. Please keep in mind that context.SaveChanges() method is used two times instead of using just after if-block as it must be in using block also.
public void Save(YourEntity entity)
{
if (entity.Id == 0)
{
context.YourEntity.Add(entity);
context.SaveChanges();
}
else
{
using (var context = new YourDbContext())
{
context.Entry(entity).State = EntityState.Modified;
context.SaveChanges(); //Must be in using block
}
}
}

Categories