I have Entity Framework set up and it works fine most of the time I need it. I have a structure like so
public partial class Topic : Entity
{
public Guid Id { get; set; }
public string Name { get; set; }
public DateTime CreateDate { get; set; }
public virtual Post LastPost { get; set; }
public virtual Category Category { get; set; }
public virtual IList<Post> Posts { get; set; }
public virtual IList<TopicTag> Tags { get; set; }
public virtual MembershipUser User { get; set; }
public virtual IList<TopicNotification> TopicNotifications { get; set; }
public virtual IList<Favourite> Favourites { get; set; }
public virtual Poll Poll { get; set; }
}
As you can see I have a number of related entities which are lists. These are mapped as standard and are lazy loaded so I can call Topic.Posts or Topic.TopicNotifications etc... (Mappings below)
HasOptional(t => t.LastPost).WithOptionalDependent().Map(m => m.MapKey("Post_Id"));
HasOptional(t => t.Poll).WithOptionalDependent().Map(m => m.MapKey("Poll_Id"));
HasRequired(t => t.Category).WithMany(t => t.Topics).Map(m => m.MapKey("Category_Id"));
HasRequired(t => t.User).WithMany(t => t.Topics).Map(m => m.MapKey("MembershipUser_Id"));
HasMany(x => x.Posts).WithRequired(x => x.Topic).Map(x => x.MapKey("Topic_Id")).WillCascadeOnDelete();
HasMany(x => x.TopicNotifications).WithRequired(x => x.Topic).Map(x => x.MapKey("Topic_Id")).WillCascadeOnDelete();
HasMany(t => t.Tags)
.WithMany(t => t.Topics)
.Map(m =>
{
m.ToTable("Topic_Tag");
m.MapLeftKey("TopicTag_Id");
m.MapRightKey("Topic_Id");
});
This is all an well. But on a couple of occasions I have the need to manually populate Topic.Posts and Topic.Favorites.
But if I try and set Topic.Posts = SomeCollection
it triggers the lazy load and loads all the posts first, and then lets me set my collection so I get two sets of sql executed (The first I don't want)
Is there anyway, to switch off the lazy loading manually on demand for just when I want to set the collection manually?
Hope that makes sense... :/
We can disable lazy loading for a particular entity or a context. To turn off lazy loading for a particular property, do not make it virtual. To turn off lazy loading for all entities in the context, set its configuration property to false.
Entity Framework supports three ways to load related data - eager loading, lazy loading and explicit loading.
Yes, lazy loading is enabled in the Entity Framework ORM too, it is on by default in Entity Framework, so if you want to enable lazy loading in Entity Framework, you don't need to do anything.
You would be better to turn off lazy loading by default and instead specify when you want to load the extra data in the first place. EF is set up to allow Eager loading by using the .Include() function on your query, with lazy loading it can get messy if you start turning it on/off for various functions, you're better to just turn it off and manage what/when you want data loaded if you're feeling a need to turn it off.
See https://msdn.microsoft.com/en-nz/data/jj574232.aspx for specific examples and a breakdown of the different ways you can eager/lazy load data. The first example shows how you could pull through posts off a blog, which is similar to what you are wanting to acheive.
var topics = context.Topics
.Include(t => t.Posts)
.ToList();
I am not aware of an approach targeted to this exact scenario so I'd have to go with a temporary disable/enable of lazy loading.
using(var context = new MyContext())
{
context.Configuration.LazyLoadingEnabled = false;
// do your thing using .Include() or .Load()
context.Configuration.LazyLoadingEnabled = true;
}
Note however that this is a global configuration so there might be a concurrency problem if that happens in your scenario.
I would not recommend turning off lazing loading on a per request basis. As AllMadHare suggests, you could turn off lazy loading entirely, but that could force changes to how you load all data. I would recommend removing the virtual keyword from Posts so that your class looks like this:
public partial class Topic : Entity
{
public Guid Id { get; set; }
public string Name { get; set; }
public DateTime CreateDate { get; set; }
public virtual Post LastPost { get; set; }
public virtual Category Category { get; set; }
public IList<Post> Posts { get; set; }
public virtual IList<TopicTag> Tags { get; set; }
public virtual MembershipUser User { get; set; }
public virtual IList<TopicNotification> TopicNotifications { get; set; }
public virtual IList<Favourite> Favourites { get; set; }
public virtual Poll Poll { get; set; }
}
Per the documentation found here: https://msdn.microsoft.com/en-us/data/jj574232.aspx#lazyOffProperty this will allow you to lazy load all other navigation properties and eager load posts if you need to.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With