The query contains references to items defined on a different data context? - c#

This throws an error saying The query contains references to items defined on a different data context. when i try to assign catName at the bottom.
this.CustomSettings = (
from xx in DBContext.ProductCustomizationMasters
where xx.ProductID == this._ProductID
select new ProductCustomization()
{
ProductID = (int)xx.ProductID,
CategoryID = (int)xx.CustomCategoryID,
CustomID = xx.CustomID,
CustomizationType = (CategoryType)xx.CustomType,
DefaultFreeCount = (short)xx.DefaultFreeCount,
IsDefaultLimit = (bool)xx.IsDefault,
HasItems = ((xx.DefaultFreeCount == 0) ? (false) : (true)),
CatName= (from yy in DBContext.CustomCategoryTbls where yy.CatID == xx.CustomCategoryID select yy.CatName).FirstOrDefault()
}
).ToList();
i am makng datacontext like this
private libDBDataContext _DB = null;
public libDBDataContext DBContext { get { return (_DB == null) ? new libDBDataContext() : _DB; } set { _DB = value; } }
how it says it has two different datacontext, while things are being performed on the same datacontext.

Every time you access your DBContext property you are creating a new libDBDataContext because you never assign it to _DB.
Try changing your code to this
private libDBDataContext _DB = null;
public libDBDataContext DBContext
{
get
{
if (_DB == null)
{
_DB = new libDBDataContext();
}
return _DB;
}
set { _DB = value; }
}
This is not thread safe, but it should help you get through your current issue.
EDIT
As #Servy pointed out there is a cleaner and thread safe implementation using Lazy.
private Lazy<libDBDataContext> _DB = new Lazy<libDBDataContext>(
() => new libDBDataContext()
);
public libDBDataContext DBContext
{
get { return _DB.Value; }
}

Related

Why am I getting an error while running this code?

When I was running a console application, I got this stack overflow error.
As this error seems to be in the Assignlogic part of my code, I have wrote down that part of code and the error which is shown. My question is how to handle this exception, without changing the functionality of code?
//Assign
public class Assignlogic
{
private List<Assign> Assigns { get; set; } = new List<Assign>();//Here exception unhandled was thrown
//System.StackOverflowException: 'Exception of type 'System.StackOverflowException' was thrown.'
readonly Assignlogic logicC = new Assignlogic();
public void AddEmployeetoProject(Assign assign, Employeelogic logicA, Projectlogic logicB)
{
List<Employee> Employes = logicA.Employees;
List<Project> Projcts = logicB.Projects;
List<Assign> Assignss = logicC.Assigns;
var id = assign.EmpId;
var pid = assign.PID;
var emp = Employes.Find(a => a.EmpId == id);
var prjct = Projcts.Find(c => c.PID == pid);
if (emp != null || prjct != null)
{
Assignss.Add(assign);
}
}
//view all assigned projects
public List<Assign> GetAllAssignedProjects()
{
return Assigns;
}
//remove an employee from a project
public void RemoveEmployee(string id)
{
var emp = Assigns.Find(a => a.EmpId == id);
if (emp != null)
{
Assigns.Remove(emp);
}
}
public bool SearchProjectbyMappedId(string id)
{
var employee = Assigns.Find(c => c.EmpId == id);
if (employee != null)
{
return true;
}
else
{
return false;
}
}
}
What happens when you create an instance of Assignlogic? This:
readonly Assignlogic logicC = new Assignlogic();
So creating an instance of Assignlogic creates an instance of Assignlogic, which creates an isntance of Assignlogic, which creates an instance of Assignlogic, etc., etc.
I don't know what your intent is here, but this is clearly not the way to do it. Objects shouldn't recursively create themselves ad infinitum.
you have this member in your class AssignLogic
readonly Assignlogic logicC = new Assignlogic();
So when you create an AssignLogic, it has to go and create an AssignLogic to put there. Creating that AssignLogic requires another AssignLogic,.......

Update Navigation Property in Entity Framework

I am a new at depth of the Entity Framework
I have just wondered why Entity Framework doesn't save changes especially the navigation property although all other properties are already updated
Please I want simple explanation
This is My Service Class
public class ProductsService
{
AppDbContext _Context;
public ProductsService()
{
_Context = new AppDbContext();
}
public Product GetProduct(int id)
{
return _Context.Products.Include(p=>p.Category).Where(pro =>pro.Id == id).SingleOrDefault();
}
public void UpdateProduct(Product product)
{
_Context.Entry(product).State = System.Data.Entity.EntityState.Modified;
_Context.SaveChanges();
}
}
In Controller:
[HttpPost]
public ActionResult Edit(NewCategoryViewModel pro,int Id)
{
CategoriesService ser = new CategoriesService();
var NewProduct = ProService.GetProduct(Id);
var NewCat = ser.GetCategory(pro.CategoryId);
NewProduct.Description = pro.Description;
NewProduct.Name = pro.Name;
NewProduct.Price = pro.Price;
NewProduct.Category = NewCat;
ProService.UpdateCategory(NewProduct);
return RedirectToAction("ProductTable");
}
I have tried this and it works fine
[HttpPost]
public ActionResult Edit(NewCategoryViewModel pro,int Id)
{
using (var Context = new AppDbContext())
{
var NewProd = Context.Products.FirstOrDefault(pr => pr.Id == Id);
var Cat = Context.Categories.FirstOrDefault(cat => cat.Id == pro.CategoryId);
Context.Entry(NewProd).State = EntityState.Modified;
NewProd.Name = pro.Name;
NewProd.Description = pro.Description;
NewProd.Price = pro.Price;
NewProd.Category = Cat;
Context.SaveChanges();
}
}
and for UpdateCategory
public void UpdateCategory(Category category)
{
using (var Context = new AppDbContext())
{
Context.Entry(category).State = System.Data.Entity.EntityState.Modified;
Context.SaveChanges();
}
}
Why the first one Not work
I know may be the problem in the state of the navigation property
Since you created the DbContext inside ProductService and you created a new Context inside:
public void UpdateCategory(Category category)
{
using (var Context = new AppDbContext())
{
Context.Entry(category).State = System.Data.Entity.EntityState.Modified;
Context.SaveChanges();
}
}
-> you use two different DbContext's together (which can cause problems with change tracking)!
Solution:
Try to use DependencyInjection for all DbContext's instead of creating them locally to prevent problems with change tracking.
You might consider using .add() instead of .entry().
.add() will also track other reachable entities.
documentation can be found here:
entity framework

ObjectDisposedException on Foreign entity

I'm quite a newbie with Linq to Sql, and I'm facing an issue regarding accessing a foreign entity.
Here is the related DB :
Table MyClass with two columns : Id, ProducerId
Table Person with two columns : Id, Affix
Here is my partial class :
public partial class MyClass
{
public string ProducerAffix
{
get { return Producer.Affix; }
}
}
And the dbml designer file where the Producer property is generated related to ProducerId foreign key :
[global::System.Data.Linq.Mapping.AssociationAttribute(Name="Person_MyClass1", Storage="_Person1", ThisKey="ProducerId", OtherKey="Id", IsForeignKey=true)]
public Person Producer
{
get
{
return this._Person1.Entity;
}
set
{
Person previousValue = this._Person1.Entity;
if (((previousValue != value)
|| (this._Person1.HasLoadedOrAssignedValue == false)))
{
this.SendPropertyChanging();
if ((previousValue != null))
{
this._Person1.Entity = null;
previousValue.MyClass.Remove(this);
}
this._Person1.Entity = value;
if ((value != null))
{
value.MyClass.Add(this);
this.ProducerId = value.Id;
}
else
{
this.ProducerId = default(System.Guid);
}
this.SendPropertyChanged("Producer");
}
}
}
When accessing MyClass' Affix property, an ObjectDisposedException is thrown...
Do I need to open a Datacontext when accessing the property ?
I read this post LINQ to SQL ObjectDisposedException on entity that never asked for but really would like avoiding creating a ViewModel...
Is there any other solution ?
Thanks a lot !
EDIT
Following JAT's answer I tried to use the DLO but don't really know how to return my foreign value from it... I found this tutorial (http://www.codeproject.com/Articles/37857/Optimizing-LINQ-Queries-using-DataLoadOptions), do I have to write a query then ?
public string Affix
{
get
{
using (var db = new DBDataContext())
{
var dlo = new DataLoadOptions();
dlo.LoadWith<Person>(p => p.Affix);
db.LoadOptions = dlo;
...
return Producer.Affix;
}
}
}
For those who might face the same issue later, I finally found out where this came from.
When I added my Person and my MyClass, I used this function :
public static Person Add(Person person)
{
using (var db = new DBDataContext())
{
db.Person.InsertOnSubmit(person);
db.SubmitChanges();
return person;
}
}
Removing the "using" did the trick for me and now I can access my foreign keys' entities.
I sincerely don't understand why because I read that "using" was a better solution than "new" because of the close issue, but seems like it does not work correctly with it, so I removed it.
public static Person Add(Person person)
{
var db = new DBDataContext();
db.Person.InsertOnSubmit(person);
db.SubmitChanges();
return person;
}

How can I log all entities change, during .SaveChanges() using EF code first?

I'm using EF code first. I'm using a base Repository for all my repositories and an IUnitofWork that inject to the repositories, too:
public interface IUnitOfWork : IDisposable
{
IDbSet<TEntity> Set<TEntity>() where TEntity : class;
int SaveChanges();
}
public class BaseRepository<T> where T : class
{
protected readonly DbContext _dbContext;
protected readonly IDbSet<T> _dbSet;
public BaseRepository(IUnitOfWork uow)
{
_dbContext = (DbContext)uow;
_dbSet = uow.Set<T>();
}
//other methods
}
e.g my OrderRepository is like this:
class OrderRepository: BaseRepository<Order>
{
IUnitOfWork _uow;
IDbSet<Order> _order;
public OrderRepository(IUnitOfWork uow)
: base(uow)
{
_uow = uow;
_order = _uow.Set<Order>();
}
//other methods
}
And I use it in this way:
public void Save(Order order)
{
using (IUnitOfWork uow = new MyDBContext())
{
OrderRepository repository = new OrderRepository(uow);
try
{
repository.ApplyChanges<Order>(order);
uow.SaveChanges();
}
}
}
Is there any way to log change histories of all entities(include their navigation properties) during .SaveChanges()? I want to log original values(before save occurs) and changed values(after save occurs).
You can get the before and after values for all changed entities by going through DbContext.ChangeTracker. Unfortunately the API is a little verbose:
var changeInfo = context.ChangeTracker.Entries()
.Where (t => t.State == EntityState.Modified)
.Select (t => new {
Original = t.OriginalValues.PropertyNames.ToDictionary (pn => pn, pn => t.OriginalValues[pn]),
Current = t.CurrentValues.PropertyNames.ToDictionary (pn => pn, pn => t.CurrentValues[pn]),
});
You can modify that to include things like the type of the entity if you need that for your logging. There is also a ToObject() method on the DbPropertyValues (the type of OriginalValues and CurrentValues) you could call if you already have a way to log whole objects, although the objects returned from that method will not have their navigation properties populated.
You can also modify that code to get all entities in the context by taking out the Where clause, if that makes more sense given your requirements.
I have overridded the default SaveChanges method to log changes for add/update/delete in entity. Though it does not cover navigation property changes.
Based on this article: Using entity framework for auditing
public int SaveChanges(string userId)
{
int objectsCount;
List<DbEntityEntry> newEntities = new List<DbEntityEntry>();
// Get all Added/Deleted/Modified entities (not Unmodified or Detached)
foreach (var entry in this.ChangeTracker.Entries().Where
(x => (x.State == System.Data.EntityState.Added) ||
(x.State == System.Data.EntityState.Deleted) ||
(x.State == System.Data.EntityState.Modified)))
{
if (entry.State == System.Data.EntityState.Added)
{
newEntities.Add(entry);
}
else
{
// For each changed record, get the audit record entries and add them
foreach (AuditLog changeDescription in GetAuditRecordsForEntity(entry, userId))
{
this.AuditLogs.Add(changeDescription);
}
}
}
// Default save changes call to actually save changes to the database
objectsCount = base.SaveChanges();
// We don't have recordId for insert statements that's why we need to call this method again.
foreach (var entry in newEntities)
{
// For each changed record, get the audit record entries and add them
foreach (AuditLog changeDescription in GetAuditRecordsForEntity(entry, userId, true))
{
this.AuditLogs.Add(changeDescription);
}
// TODO: Think about performance here. We are calling db twice for one insertion.
objectsCount += base.SaveChanges();
}
return objectsCount;
}
#endregion
#region Helper Methods
/// <summary>
/// Helper method to create record description for Audit table based on operation done on dbEntity
/// - Insert, Delete, Update
/// </summary>
/// <param name="dbEntity"></param>
/// <param name="userId"></param>
/// <returns></returns>
private List<AuditLog> GetAuditRecordsForEntity(DbEntityEntry dbEntity, string userId, bool insertSpecial = false)
{
List<AuditLog> changesCollection = new List<AuditLog>();
DateTime changeTime = DateTime.Now;
// Get Entity Type Name.
string tableName1 = dbEntity.GetTableName();
// http://stackoverflow.com/questions/2281972/how-to-get-a-list-of-properties-with-a-given-attribute
// Get primary key value (If we have more than one key column, this will need to be adjusted)
string primaryKeyName = dbEntity.GetAuditRecordKeyName();
int primaryKeyId = 0;
object primaryKeyValue;
if (dbEntity.State == System.Data.EntityState.Added || insertSpecial)
{
primaryKeyValue = dbEntity.GetPropertyValue(primaryKeyName, true);
if(primaryKeyValue != null)
{
Int32.TryParse(primaryKeyValue.ToString(), out primaryKeyId);
}
// For Inserts, just add the whole record
// If the dbEntity implements IDescribableEntity,
// use the description from Describe(), otherwise use ToString()
changesCollection.Add(new AuditLog()
{
UserId = userId,
EventDate = changeTime,
EventType = ModelConstants.UPDATE_TYPE_ADD,
TableName = tableName1,
RecordId = primaryKeyId, // Again, adjust this if you have a multi-column key
ColumnName = "ALL", // To show all column names have been changed
NewValue = (dbEntity.CurrentValues.ToObject() is IAuditableEntity) ?
(dbEntity.CurrentValues.ToObject() as IAuditableEntity).Describe() :
dbEntity.CurrentValues.ToObject().ToString()
}
);
}
else if (dbEntity.State == System.Data.EntityState.Deleted)
{
primaryKeyValue = dbEntity.GetPropertyValue(primaryKeyName);
if (primaryKeyValue != null)
{
Int32.TryParse(primaryKeyValue.ToString(), out primaryKeyId);
}
// With deletes use whole record and get description from Describe() or ToString()
changesCollection.Add(new AuditLog()
{
UserId = userId,
EventDate = changeTime,
EventType = ModelConstants.UPDATE_TYPE_DELETE,
TableName = tableName1,
RecordId = primaryKeyId,
ColumnName = "ALL",
OriginalValue = (dbEntity.OriginalValues.ToObject() is IAuditableEntity) ?
(dbEntity.OriginalValues.ToObject() as IAuditableEntity).Describe() :
dbEntity.OriginalValues.ToObject().ToString()
});
}
else if (dbEntity.State == System.Data.EntityState.Modified)
{
primaryKeyValue = dbEntity.GetPropertyValue(primaryKeyName);
if (primaryKeyValue != null)
{
Int32.TryParse(primaryKeyValue.ToString(), out primaryKeyId);
}
foreach (string propertyName in dbEntity.OriginalValues.PropertyNames)
{
// For updates, we only want to capture the columns that actually changed
if (!object.Equals(dbEntity.OriginalValues.GetValue<object>(propertyName),
dbEntity.CurrentValues.GetValue<object>(propertyName)))
{
changesCollection.Add(new AuditLog()
{
UserId = userId,
EventDate = changeTime,
EventType = ModelConstants.UPDATE_TYPE_MODIFY,
TableName = tableName1,
RecordId = primaryKeyId,
ColumnName = propertyName,
OriginalValue = dbEntity.OriginalValues.GetValue<object>(propertyName) == null ? null : dbEntity.OriginalValues.GetValue<object>(propertyName).ToString(),
NewValue = dbEntity.CurrentValues.GetValue<object>(propertyName) == null ? null : dbEntity.CurrentValues.GetValue<object>(propertyName).ToString()
}
);
}
}
}
// Otherwise, don't do anything, we don't care about Unchanged or Detached entities
return changesCollection;
}
you have scared people away with the extra requirement
Include their navigation properties
This is simply a non trivial exercise.
And if this is important, you should manage/track changes across references with code.
this is a sample covering this topic
Undo changes in entity framework entities
There is a sample doing close top what you want here
undo changes
It can easily be converted to load before and after images elsewhere.
Given the ObjectState entry after DetectChanges is called, you can implement a simple entity by entity option. and per UOW. But the navigation / references version makes this very complex as you worded the requirement.
EDIT : How to access the changeList
public class Repository<TPoco>{
/....
public DbEntityEntry<T> Entry(T entity) { return Context.Entry(entity); }
public virtual IList<ChangePair> GetChanges(object poco) {
var changes = new List<ObjectPair>();
var thePoco = (TPoco) poco;
foreach (var propName in Entry(thePoco).CurrentValues.PropertyNames) {
var curr = Entry(thePoco).CurrentValues[propName];
var orig = Entry(thePoco).OriginalValues[propName];
if (curr != null && orig != null) {
if (curr.Equals(orig)) {
continue;
}
}
if (curr == null && orig == null) {
continue;
}
var aChangePair = new ChangePair {Key = propName, Current = curr, Original = orig};
changes.Add(aChangePair);
}
return changes;
}
///... partial repository shown
}
// FYI the simple return structure
public class ChangePair {
public string Key { get; set; }
public object Original { get; set; }
public object Current { get; set; }
}
DbContext has ChangeTracker property.
You can override .SaveChanges() in your context and log changes.
I don't think that entity framework can do it for you. Probably, you must detect changes directly in your model classes.
I've expanded on Steve's answer to provide a check for Changed, Added, and Deleted entities and print them in a sensible way.
(My use case is to ensure there are no unsaved changes before disposing of a DbContext instance, but this check could be done at any point)
/// <summary>Helper method that checks whether the DbContext had any unsaved changes before it was disposed.</summary>
private void CheckForUnsavedChanges(DbContext dbContext)
{
try
{
List<DbEntityEntry> changedEntityEntries = dbContext.ChangeTracker.Entries()
.Where(t => t.State != EntityState.Unchanged && t.State != EntityState.Detached).ToList();
if (!changedEntityEntries.Any())
return;
throw new Exception("Detected that there were unsaved changes made using a DbContext. This could be due to a missing call to `.SaveChanges()` or possibly " +
"some read-only operations that modified the returned entities (in which case you might wish to use `.AsNoTracking()` in your query). Changes:\n " +
String.Join("\n ", changedEntityEntries.Select(entry => $"{entry.Entity.GetType()} {entry.State}:\n " + String.Join("\n ",
entry.State == EntityState.Modified ? entry.CurrentValues.PropertyNames
// Only output properties whose values have changed (and hope they have a good ToString() implementation)
.Where(pn => entry.OriginalValues?[pn] != entry.CurrentValues[pn])
.Select(pn => $"{pn} ({entry.OriginalValues?[pn]} -> {entry.CurrentValues[pn]})") :
// Added or Deleted entities are output in their entirety
entry.State == EntityState.Added ? entry.CurrentValues.PropertyNames.Select(pn => $"{pn} = {entry.CurrentValues[pn]}") :
/* entry.State == EntityState.Deleted ? */ entry.CurrentValues.PropertyNames.Select(pn => $"{pn} = {entry.OriginalValues[pn]}")))));
}
catch (Exception ex)
{
_logger.Error("Issue encountered when checking for unsaved changes.", ex);
}
}

An object with a key that matches the key of the supplied object could not be found in the ObjectStateManager

I want to update record from FormView with ObjectDataSource and lose my day to solve this error.
An object with a key that matches the key of the supplied object could
not be found in the ObjectStateManager. Verify that the key values of
the supplied object match the key values of the object to which
changes must be applied.
My code is below
private static Entities1 _db = null;
public static Entities1 CreateDataContext()
{
if (_db == null)
{
_db = new Entities1(System.Configuration.ConfigurationManager.ConnectionStrings["Entities1"].ConnectionString);
_db.games.MergeOption = MergeOption.NoTracking;
_db.my_aspnet_users.MergeOption = MergeOption.NoTracking;
_db.platforms.MergeOption = MergeOption.NoTracking;
}
return _db;
}
public void Update(game item)
{
Entities1 DB = CreateDataContext();
item.modified = DateTime.Now;
var obj = (from u in DB.games
where u.idgames == item.idgames
select u).First();
DB.games.ApplyCurrentValues(item);//Error Here
DB.SaveChanges();
}
In your method:
public void Update(game item)
{
Entities1 DB = CreateDataContext();
item.modified = DateTime.Now;
var obj = (from u in DB.games
where u.idgames == item.idgames
select u).First();
DB.games.ApplyCurrentValues(item);//Error Here
DB.SaveChanges();
}
item is not attached so it can't be updated. That's pretty much what the error message is telling you, too.
It looks like you'd want to use obj which is retrieved from your context. Then set the values of obj to those in item, and use obj to make the updates.
EDIT for sample...
If you just want to set the modified date and time you'd do this:
public void Update(game item) {
Entities1 DB = CreateDataContext();
var obj = (from u in DB.games
where u.idgames == item.idgames
select u).SingleOrDefault();
if (obj == null) {
// handle the case where obj isn't found
// probably by throwing an exception
}
obj.modified = DateTime.Now;
DB.games.ApplyCurrentValues(obj);
DB.SaveChanges();
}

Categories

Resources