Entity Framework: How to disable lazy loading for specific query? - c#

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;
} ​

Related

How to test that lazy loading is working in Entity Framework

The context is set up for lazy loading and seems that everything is working properly but:
public void Test_Lazy_Loading() {
using (var context = new MyDbContext()) {
var student = context.Students.First();
var loaded = context.Entry(student).Collection(e => e.Classes).IsLoaded; // returns true
Assert.IsFalse(loaded); // fails
}
}
Does this test mean that CLasses is eager loaded?
What is the best way to test that lazy loading is working?

Lazy Loading and multiple references

My Database is set up with an Entity table, which has a Ref_Type navigation property (and a FK which references TypeID). The Type table, has a Ref_Department, same FK setup. Finally, the Department table has a Ref_Locale and same FK setup.
I save the Entities in a List, which is a property of a singleton. It is created as follows;
private Singleton()
{
using (Database db = new Database())
{
List<Entities> EntityList = db.Entities.ToList<Entities>();
}
}
This is fine, the navigation properties are ALL loaded and I can access any one of them.
The problem comes when I update an Entity entry as follows;
public void UpdateEntity(Entities oldEnt, Entities newEnt)
{
using (Database db = new Database())
{
Entities ent = db.Entities.Where(e => e.EntityName == oldEnt.EntityName).FirstOrDefault();
ent.EntityName = newEnt.EntityName;
ent.EntityEmail = newEnt.EntityEmail;
...
ent.EntityType_ID = newEnt.EntityType_ID;
db.SaveChanges();
}
RefreshEntities();
}
public void RefreshEntities()
{
using (Database db = new Database())
{
db.Configuration.LazyLoadingEnabled = false;
db.SaveChanges();
EntityList = db.Entities.Include("Ref_EntityType").Include("Ref_EntityPosition").ToList<Entities>();
}
}
Ref_Entity gets loaded properly, but then within Ref_Entity, Ref_Department is just null. I've tried just using db.Entities.ToList<Entities>(); like in my constructor, no dice. As you can see, I've also tried turning LazyLoading off (I thought I might need to call SaveChanges() for it to actually apply the flag). I've also tried .Include("Ref_Department") but it just complains that it doesn't exist for Entities, which makes sense.
The newEnt that I pass to the UpdateEntity method does not have Ref_Type initialised, I'm working under the assumption that anything not changed in the UpdateEntity method would just stay the same...
So now I'm at a bit of a loss as to what's going on and how to fix it. If anyone could help explain where I'm going wrong or give me some pointers about how to fix my code to make it work, that would be great.
On a whim, I modified RefreshEntities() to;
EntityList = db.Entities.Include("Ref_EntityPosition").Include("Ref_EntityType").
Include("Ref_EntityType.Ref_Department").
Include("Ref_EntityType.Ref_Department.Ref_Locale").ToList<Entities>();
And now I'm getting all the references.
I'm still not sure why it would load all the references in the constructor but not in the RefreshEntities() method, even if the calls are identical, but this solves the problem so I'm happy enough to leave it like that.

Multiple instances of IEntityChangeTracker Error

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.

How to access entity's properties outside context using Entity Framework?

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.

How to relate objects from multiple contexts using the Entity Framework

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;

Categories

Resources