I am very new to the entity framework, so please bear with me...
How can I relate two objects from different contexts together?
The example below throws the following exception:
System.InvalidOperationException: The
relationship between the two objects
cannot be defined because they are
attached to different ObjectContext
objects.
void MyFunction()
{
using (TCPSEntities model = new TCPSEntities())
{
EmployeeRoles er = model.EmployeeRoles.First(p=>p.EmployeeId == 123);
er.Roles = GetDefaultRole();
model.SaveChanges();
}
}
private static Roles GetDefaultRole()
{
Roles r = null;
using (TCPSEntities model = new TCPSEntities())
{
r = model.Roles.First(p => p.RoleId == 1);
}
return r;
}
Using one context is not an option because we are using the EF in an ASP.NET application.
You will have to use the same context (you can pass the context to the getdefaultrole method) or rethink the relationships and extend the entity.
EDIT: Wanted to add this was for the example provided, using asp.net will require you to fully think out your context and relationship designs.
You could simply pass the context.. IE:
void MyFunction()
{
using (TCPSEntities model = new TCPSEntities())
{
EmployeeRoles er = model.EmployeeRoles.First(p=>p.EmployeeId == 123);
er.Roles = GetDefaultRole(model);
model.SaveChanges();
}
}
private static Roles GetDefaultRole(TCPSEntities model)
{
Roles r = null;
r = model.Roles.First(p => p.RoleId == 1);
return r;
}
Another approach that you could use here is to detach objects from one context, and then attach them to another context. That's a bit of a hack, and it may not work in your situation, but it might be an option.
public void GuestUserTest()
{
SlideLincEntities ctx1 = new SlideLincEntities();
GuestUser user = GuestUser.CreateGuestUser();
user.UserName = "Something";
ctx1.AddToUser(user);
ctx1.SaveChanges();
SlideLincEntities ctx2 = new SlideLincEntities();
ctx1.Detach(user);
user.UserName = "Something Else";
ctx2.Attach(user);
ctx2.SaveChanges();
}
Yep - working across 2 or more contexts is not supported in V1 of Entity Framework.
Just in case you haven't already found it, there is a good faq on EF at http://blogs.msdn.com/dsimmons/pages/entity-framework-faq.aspx
From what I understand, you want to instantiate your model (via the "new XXXXEntities()" bit) as rarely as possible. According to MS (http://msdn.microsoft.com/en-us/library/cc853327.aspx), that's a pretty substantial performance hit. So wrapping it in a using() structure isn't a good idea. What I've done in my projects is to access it through a static method that always provides the same instance of the context:
private static PledgeManagerEntities pledgesEntities;
public static PledgeManagerEntities PledgeManagerEntities
{
get
{
if (pledgesEntities == null)
{
pledgesEntities = new PledgeManagerEntities();
}
return pledgesEntities;
}
set { pledgesEntities = value; }
}
And then I retrieve it like so:
private PledgeManagerEntities entities = Data.PledgeManagerEntities;
Related
I'm currently working on an ASP.NET MVC 4.5 application. I'm using the Repository Pattern in my BLL. I'm trying to implement the Update method and map updatedOffer(vm) to my originalOffer(poco).
To respect DRY and not duplicate the code in Create and Update, I use the method OfferVmToOffer to generate a new poco from my viewmodel.
Anyways, I'm getting this error when I try to "update" the originalOffer:
A referential integrity constraint violation occurred: The property value(s) of on one end of a relationship do not match the property value(s) on the other end
public void UpdateOffer(OfferVm updatedOffer)
{
var originalOffer = Db.Offer.FirstOrDefault(o => o.OfferId == updatedOffer.OfferId);
if(originalOffer != null)
{
var tmpOffer = OfferVmToOffer(updatedOffer);
tmpOffer.ActorPoolId = originalOffer.ActorPoolId;
tmpOffer.SkillPoolId = originalOffer.SkillPoolId;
tmpOffer.SwotPoolId = originalOffer.SwotPoolId;
tmpOffer.TargetPoolId = originalOffer.TargetPoolId;
tmpOffer.OfferData.DeliveryModelPoolId = originalOffer.OfferData.DeliveryModelPoolId;
originalOffer = tmpOffer;
// mark as modified => here i'm getting the error
Db.Entry(originalOffer).State = EntityState.Modified;
Db.SaveChanges();
}
}
Do you have an idea on how to solve this issue?
Thanks
It's kind of difficult to answer without seeing Offer model, OfferVm and OfferVmToOffer view models, but what about updating your code to the following?
public void UpdateOffer(OfferVm updatedOffer)
{
var originalOffer = Db.Offer.FirstOrDefault(o => o.OfferId == updatedOffer.OfferId);
if(originalOffer != null)
{
originalOffer.ActorPoolId = updatedOffer.ActorPoolId;
originalOffer.SkillPoolId = updatedOffer.SkillPoolId;
originalOffer.SwotPoolId = updatedOffer.SwotPoolId;
originalOffer.TargetPoolId = updatedOffer.TargetPoolId;
originalOffer.OfferData.DeliveryModelPoolId = updatedOffer.OfferData.DeliveryModelPoolId;
Db.Entry(originalOffer).State = EntityState.Modified;
Db.SaveChanges();
}
}
Is there any way to disable lazy loading for specific query on Entity Framework 6? I want to use it regularly, but sometimes I want to disable it. I'm using virtual properties to lazy load them.
set the following code before the query you want to execute
context.Configuration.LazyLoadingEnabled = false;
You can disable Lazy loading for a specific query as follows :
public static Cursos GetDatosCursoById(int cursoId)
{
using (var bd = new AcademyEntities())
{
try
{
bd.Configuration.ProxyCreationEnabled = false;
return bd.Cursos.FirstOrDefault(c => c.cursoId == cursoId);
}
catch (Exception ex)
{
return null;
}
}
}
I might be missing something here, but rather than changing the configuration each time, might another approach be to use .Include() on only those queries where you want to eager load?
Suppose we have a Product class which has a navigation property to a Colour class, you might load the Colour for a Product like this -
var product = _context.Products
.Where(p => p.Name == "Thingy")
.Include(x => x.Colours)
.ToList();
In EF Core: context.ChangeTracker.LazyLoadingEnabled = false;
Per this answer.
Go to your diagram properties and find a property designated to lazy loading and disable it.
If you are using code first then go to your config area and disable it from there with:
this.Configuration.LazyLoadingEnabled = false;
Another approcah for another EF Version (Entity Framework 5)
//Note: ContextOptions instead of ChangeTracker or Configuration
context.ContextOptions.LazyLoadingEnabled = false;
Suppose you have this:
IOrderedQueryable<Private.Database.DailyItem> items;
using (var context = new Private.Database.PrivateDb())
{
context.Configuration.LazyLoadingEnabled = false;
items = context.DailyItem.OrderBy(c => c.sortOrder).OrderByDescending(c => c.isFavorite);
}
You'd still get lazy loading, despite the explicit setting of not to. The fix is easy, change it to this:
List<Private.Database.DailyItem> items;
using (var context = new Private.Database.PrivateDb())
{
// context.Configuration.LazyLoadingEnabled = false;
items = context.DailyItem.OrderBy(c => c.sortOrder).OrderByDescending(c => c.isFavorite).ToList();
}
For EF Core to make it simple with a method you can use this helper:
public static AppDbContext DisableLazyLoading(this AppDbContext dbcontext)
{
dbcontext.ChangeTracker.LazyLoadingEnabled = false;
return dbcontext;
}
Using
return dbcontext.DisableLazyLoading().Branches.Find(course.BranchId);
i just do this in every class that need disable lazy loading and in every class just call the db without lazyloading everything work fine
private DataContext db;
public TheClass ()
{
db = new DataContext(ConString);
db.Configuration.LazyLoadingEnabled = false;
}
I'm hoping this will be an easy one but for the life of me, I cannot find the specific answer elsewhere on SO or any other site.
I have a basic repository/unit of work pattern with Entity Framework Code First. It all works smoothly except for certain cases of Update. THe problem is I have a set of Entity Framework model objects, all prefixed with "Db" which EF returns, but I then convert them to plain DataContract Model objects to pass to the Web layer to give separation of concerns. I have a basic conversion interface that just populates a WebModel object from the DataModel object, copying field by field verbatim.
So if you retrieve a DbUser object from EF with ID of 1, then convert to a User object, then convert that BACK to a DbUser object, you end up with a DbUser with ID of 1, but it is a DIFFERENT object to the one you started with, though they have the same primary key field, the actual CLR objects themselves are different.
The following works
User user;
using (var work = new UnitOfWork())
{
var repository = new UserDataRepository(work);
user = repository.Get(1);
repository.save();
}
var modelUser = DataConverter.Convert(user);
modelUser.Name = "new name";
user = BusinessConverter.Convert(modelUser);
using (var work = new UnitOfWork())
{
var repository = new UserDataRepository(work);
repository.Update(user);
repository.save();
}
As they are using two different unit of works/contexts, so the second block has nothing in the ObjectStateManager to compare to and can just attach the detached object in the Update() methods
This, however does NOT work
using (var work = new UnitOfWork())
{
var repository = new UserDataRepository(work);
user = repository.Get(1);
repository.save();
var modelUser = DataConverter.Convert(user);
modelUser.Name = "new name";
user = BusinessConverter.Convert(modelUser)
repository.Update(user);
repository.save();
}
NOTE: I know logically this doesn't make much sense to convert and just convert back but go with it, I've simplified the example greatly to make it easier to put into paper, in my actual code there is a reason for doing it that way.
I get the usual error "an object with the same key already exists in the objectstatemanager...". I'm assuming because the Get() loads the object into EF and then the update sees that the object is detached, then tries to attach it and it already exists.
My Update method in my repository is as below
public override bool UpdateItem(DbUser item)
{
if (Work.Context.Entry(item).State == EntityState.Detached)
Work.Context.Users.Attach(item);
Work.Context.Entry(item).State = EntityState.Modified;
return Work.Context.Entry(item).GetValidationResult().IsValid;
}
I made this Extension method to the DbContext to ReAttach the Entity without problems try it out:
public static void ReAttach<T>(this DbContext context, T entity) where T : class
{
var objContext = ((IObjectContextAdapter) context).ObjectContext;
var objSet = objContext.CreateObjectSet<T>();
var entityKey = objContext.CreateEntityKey(objSet.EntitySet.Name, entity);
Object foundEntity;
var exists = objContext.TryGetObjectByKey(entityKey, out foundEntity);
// Detach it here to prevent side-effects
if (exists)
{
objContext.Detach(foundEntity);
}
context.Set<T>().Attach(entity);
}
Then just update your method :
public override bool UpdateItem(DbUser item)
{
Work.Context.ReAttach(item);
Work.Context.Entry(item).State = EntityState.Modified;
return Work.Context.Entry(item).GetValidationResult().IsValid;
}
You might get a manged Entity, and again verbatim map the new DbUser's properties to the managed Object:
public override bool UpdateItem(DbUser item)
{
using (var work = new UnitOfWork())
{
var repository = new UserDataRepository(work);
DbUser managedUser = repository.Get(item.PK);
//foreach DbUser property map the item to managedUser
managedUser.field1 = item.field1;
[..]
repository.Update(managedUser);
repository.Save();
}
}
If you set your context to AsNoTracking() this will stop aspmvc tracking the changes to the entity in memory (which is what you want anyway on the web).
_dbContext.Products.AsNoTracking().Find(id);
I would recommend you read more about this at http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/advanced-entity-framework-scenarios-for-an-mvc-web-application
Yash
I've read through at least a dozen other questions just like this one, but I am having trouble grasping some of this stuff.
I'm used to developing ASP.NET MVC3 with repositories and code-first entities linking to the entity framework.
I've recently switched to database-first ADO.NET with services development.
I find this to be very clean since I can access stuff through my foreign keys.
Anyway, my old save methods seem to be broken since I constantly get this error
An entity object cannot be referenced by multiple instances of
IEntityChangeTracker
So here's a look at my save action and my service:
Action:
[HttpPost]
public ActionResult AddReview(Review review, int id)
{
User loggedInUser = userService.GetUserByusername(User.Identity.Name);
review.WriterId = loggedInUser.UserId;
review.ProductId = id;
if (ModelState.IsValid)
{
reviewService.Save(review);
Product product = productService.GetProduct(id);
if(product.Quantity>=1)
product.Quantity--;
product.TimesBought++;
productService.UpdateRating(product, reviewService);
loggedInUser.GoldCoins -= product.Price;
Session["goldCoins"] = loggedInUser.GoldCoins;
userService.Save(loggedInUser);
productService.Save(product);
}
else
{
return View(review);
}
return RedirectToAction("Index", "Answers", new { reviewId = review.ReviewId });
Service:
public class ReviewService : Service<Review, CapstoneEntities>
{
...
public void Save(Review review)
{
using (var db = new CapstoneEntities())
{
if (review.ReviewId == 0)
{
db.Reviews.Add(review);
db.Entry(review).State = EntityState.Added;
}
else
{
db.Entry(review).State = EntityState.Modified;
}
db.SaveChanges();
}
}
}
My suspicion is with this line of code: using (var db = new CapstoneEntities()) but I'm not sure how else to do this. Again, this worked perfectly with my old way of doing things but now I get errors on just about ever CRUD operation.
Thank you.
It looks like this is being caused by having an entity belong to multiple DataContexts. Whatever code that is calling that action should use the same DataContext to create the entity as the one used to persist it to the datastore.
In most instances you should only keep one instance of the DataContext. You can use a DI framework like Castle to define/store a dependency (in this case the DataContext) as Transient or PerWebRequest and inject it into the service and controller, so you'll always have a reference to the same instance of the DataContext.
I am new to MVC & Entity frame work. I got same problem after fighting a lot
This solution worked for me. Hope it can be useful for you guys.
var mediaItem = db.MediaItems.FirstOrDefault(x => x.Id == mediaItemViewModel.Id);
mediaItem.Name = mediaItemViewModel.Name;
mediaItem.Description = mediaItemViewModel.Description;
mediaItem.ModifiedDate = DateTime.Now;
mediaItem.FileName = mediaItem.FileName;
mediaItem.Size = KBToMBConversion(mediaItemViewModel.Size);
mediaItem.Type = mediaItem.Type;
//db.Entry(mediaItem).State = EntityState.Modified;// coment This line
db.SaveChanges();
Cause you are reading the the whole object from db and holding it in the current context and when you try to modify the entity state its tells you already one entity attached to the current context. just call save changes it will save it.
I'm new to Entity Framework (working mostly with NHibernate with ActiveRecord before) and I'm stuck with something, that I think should be easy...
I have a User Entity, and created partial User class so I can add some methods (like with NHibernate). I added GetByID to make getting user easier:
public static User GetByID(int userID)
{
using (var context = new MyEntities())
{
return context.Users.Where(qq => qq.UserID == userID).Single();
}
}
Now in the same class I want to log moment of logging in, and I try to do:
public static void LogLoginInfo(int userID)
{
using (var context = new MyEntities())
{
var user = User.GetByID(userID);
var log = new LoginLog { Date = DateTime.Now };
user.LoginLogs.Add(log);
context.SaveChanges();
}
}
The problem is I can't access user.LoginLogs because user's context is already disposed... Most likely I'm missing something obvious here, but creating always full queries like:
context.Users.Where(qq => qq.UserID == userID).Single().LoginLogs.Add(log);
doesn't seem like a good option...
I've read about Repository pattern but I think it's too big gun for such task. Please explain me what am I doing wrong. Thanks in advance!
EDIT
To picture what I'd like to do:
//somewhere in business logic
var user = User.GetByID(userID);
var posts = user.GetAllPostsForThisMonth();
foreach(var post in posts)
{
Console.WriteLine(post.Answers.Count);
}
Normally I'm not allowed to do this because I can't get post.Answers without context...
You are closing the object context and then trying to add a log to the user that is detached. You need to attach the user so the objectContext know what has been changed or added.
public static void LogLoginInfo(int userID)
{
using (var context = new MyEntities())
{
var user = context.User.Where(p=>p.UserID == userID); //<= The Context now knows about the User, and can track changes.
var log = new LoginLog { Date = DateTime.Now };
user.LoginLogs.Add(log);
context.SaveChanges();
}
}
Update
You can also attach the object.
public static void LogLoginInfo(int userID)
{
using (var context = new MyEntities())
{
var user = User.GetByID(userID);
var log = new LoginLog { Date = DateTime.Now };
user.LoginLogs.Add(log);
context.User.Attach(user);
context.SaveChanges();
}
}
Update
var getFirstLogin = from p in User.GetUserById(userId)
select p.LoginLogs.FirstOrDefault();
NB if LoginLogs is a different table you will need to use Include.
public static User GetByID(int userID)
{
using (var context = new MyEntities())
{
return context.Users.Include("LoginLogs").Where(qq => qq.UserID == userID).FirstOrDefault();
}
}
If you are open to using stored procedures (and they work nicely with EF), you can return the user object and simultaneously add to the log table with a single call to the database.
I used to do everything with SP's in my pre-EF/ORM days, when I went to EF I tried very hard to avoid using stored procedures to avoid falling back into my old habits, but now I have found that the selective use of stored procedures you can have the benefits of both -the EF way of doing things, and the super functionality/performance that a well written SP can provide.