In the ADO.Net Entity Framework, I have an object which has 4 references to other objects. For some reason, when I query those references, two of them load automatically (as expected), and two of them always return null.
Bizarrely enough, when I manually ask the references to load, they load just dandy.
As an example:
if (account.HoldingEntity == null &&
account.HoldingEntityReference.EntityKey != null) {
account.HoldingEntityReference.Load();
account.HoldingEntity = account.HoldingEntityReference.Value;
}
When I first check the HoldingEntity it is always null, however the Load will return the HoldingEntity without problem.
Any clues?
Thanks!
Using ADO.NET Entities, you need to specify what entities you want to load automatically with Include, as in
Dim entity = (From e in db.Entities.Include("SubEntity"))
As others have said you need to .Include() in v1 to avoid needing to call .Load()
In 4.0 you will be able to set DeferredLoadingEnabled on your ObjectContext (I think we are changing this name to the more appropriate LazyLoadingEnabled in time for Beta2).
As for why you get 2 relationships already loaded anyway. That is probably a side-effect of something called Relationship Fix-up.
When two related entities are in the same Context, they automatically get their relationship's fixed to point to each other. So if (as I suspect) 2 of the 4 entities are already in your context, when you do the query, you will end up in a situation where 2 of your relationships are loaded, even though you didn't call .Include() or .Load().
Hope this helps
Cheers
Alex
This was done in EF v1 as a design decision, and many developers actually prefer having explicit control over if and when referenced properties will be loaded.
For EF v4 coming out with .NET 4.0 before the end of 2009, you'll have the option to turn on automatic deferred loading, if you so wish. See this blog post on the ADO.NET team blog for more information on deferred loading in EF v4.
Marc
Related
We have a Repository class. While this class has some custom behavior, it wraps a standard ObjectContext object and so it's primarily standard Entity Framework.
Currently, we have the following code block, which works but performs horribly. (target is a CostingLineItem. The code changes the AddedByEmployee reference for this CostingLineItem.)
if (target.AddedByEmployee != null)
target.AddedByEmployee.CostingLineItems.Remove(target);
byEmployee.CostingLineItems.Add(target);
target.AddedByEmployee = byEmployee;
Because we have lazy loading enabled, this bit of code loads both the target.AddedByEmployee.CostingLineItems and byEmployee.CostingLineItems collections, which could be many thousands of rows.
Unfortunately, I can't change the lazy loading setting for this code. I need to find a way to make it more efficient, but nothing seems to work for me.
Here's what I've tried so far.
Method 1:
target.AddedByEmployeeId = byEmployee.Id;
Has no effect. The AddedByEmployeeId column still contains the original value. Apparently, the original employee reference is still there and takes priority.
Method 2:
target.AddedByEmployee = byEmployee;
Throws the following exception. Again, seems the original employee reference is still there.
Multiplicity constraint violated. The role 'Employees' of the relationship 'Leo.Domain.FK_CostingLineItem_Employees' has multiplicity 1 or 0..1.
Method 3:
Repository.Detach(target.AddedByEmployee);
target.AddedByEmployee = byEmployee;
Detach() (which in turn calls ObjectContext.Detach()) throws the following exception:
The object cannot be detached because it is not attached to the ObjectStateManager.
Method 4:
target.AddedByEmployee.CostingLineItems.Remove(target);
target.AddedByEmployee = byEmployee;
This works! But it's still loading target.AddedByEmployee.CostingLineItems, which I would like to avoid.
I realize I have not shown all of our code here (that's just not possible). But the code is using a standard ObjectContext underneath. What I would really like is someone who has some insights into Entity Framework and can offer some ideas for what else I can try, or what else I can check.
Note: We are currently running Visual Studio 2012. I will see if we can update to 2015. I would love to know if anything has changes since the version we are using that could make some of the methods above work where they didn't before.
Have you tried removing the target directly from the DbSet<> rather that removing it from the attached CostingLineItems.
context.Set<CostingLineItems>().Remove(target)
This should remove the target without loading the collection.
After some extensive research and testing, I think I determined what my issues were.
The problem was that the entity in question had just been cloned in the database. The cloning code follows a bunch of rules that dictate if related items are also cloned or only the references are cloned.
Either way, the AddedByEmployee had already been set. And so trying to set it a second time, or simply trying to set the ID has problems because of the conflict with what was already set.
I would like to know if the following scenario is possible with Entity Framework:
I want to load several tables with the option AsNoTracking since they are all like static tables that cannot be changed by user.
Those tables also happen to be navigation property of others. Up till now I relied on the AutoMapping feature of the Entity Framework, and don't use the .Include() or LazyLoading functionality.
So instead of:
var result = from x in context.TestTable
.Include("ChildTestTable")
select x;
I am using it like this:
context.ChildTestTable.Load();
context.TestTable.Load();
var result = context.TestTable.Local;
This is working smoothly because the application is so designed that the tables within the Database are very small, there won't be a table that exceeds 600 rows (and that's already pretty high value in my app).
Now my way of loading data, isn't working with .AsNoTracking().
Is there any way to make it working?
So I can write:
context.ChildTestTable.AsNoTracking().List();
var result = context.TestTable.AsNoTracking().List();
Instead of:
var result = from x in context.TestTable.AsNoTracking()
.Include("ChildTestTable")
select x;
So basically, I want to have 1 or more tables loaded with AutoMapping feature on but without loading them into the Object State Manager, is that a possibility?
The simple answer is no. For normal tracking queries, the state manager is used for both identity resolution (finding a previously loaded instance of a given entity and using it instead of creating a new instance) and fixup (connecting navigation properties together). When you use a no-tracking query it means that the entities are not tracked in the state manager. This means that fixup between entities from different queries cannot happen because EF has no way of finding those entities.
If you were to use Include with your no-tracking query then EF would attempt to do some fixup between entities within the query, and this will work a lot of the time. However, some queries can result in referencing the same entity multiple times and in some of those cases EF has no way of knowing that it is the same entity being referenced and hence you may get duplicates.
I guess the thing you don't really say is why you want to use no-tracking. If your tables don't have a lot of data then you're unlikely to see significant perf improvements, although many factors can influence this. (As a digression, using the ObservableCollection returned by .Local could also impact perf and should not be necessary if the data never changes.) Generally speaking you should only use no-tracking if you have an explicit need to do so since otherwise it ends up adding complexity without benefit.
I am adding new entity to the context and I would like populate all its references collections once the add is done. Issue is, I am reading the same entity from the context which I created during the add(), basically EF doesn't go to the DB. This is correct behaviour, but how do I get around it ?
Repo().Add(newEntity);
Repo().Reload(newEntity);
This reloads the entity from DB however I am not getting the references (FK relations). I have found how to load the reference, however I would need a generic way how to load all the references for any entity.
var entry = Context.Entry(entity);
entry.Reference("ReferenceName").Load();
Is the above the correct approach or is there some other way ?
Without seeing your repository code, I am guessing it's a lazy loading issue.
This site explains eager vs lazy loading: http://msdn.microsoft.com/en-us/data/jj574232.aspx
You can either specify exactly what references you want to bring back by using the .Include() in your repo (good for long chains where you dont need everything).
context.Set<whateverType>.Include(t => t.(whatever you are referencing)).Where(t => t.id = id);
Or you can specify the context to use eager loading and bring back everything with your retrieval.
context.LazyLoadingEnabled = false;
I've got a couple of entities in a parent-child relationship: Family (parent) and Updates (child). I want to read a list of families without the corresponding updates. There are only 17 families but about 60,000 updates so I really don't want the updates.
I used EntitiesToDTOs to generate a DTO from the Family entity and to create an assembler for converting the Family entity to the FamilyDTO. The ToDTO method of the assembler looks like:
public static FamilyDTO ToDTO(this Family entity)
{
if (entity == null) return null;
var dto = new FamilyDTO();
dto.FamilyCode = entity.FamilyCode;
dto.FamilyName = entity.FamilyName;
dto.CreateDatetime = entity.CreateDatetime;
dto.Updates_ID = entity.Updates.Select(p => p.ID).ToList();
entity.OnDTO(dto);
return dto;
}
When I run the assembler I find each resulting FamilyDTO has the Updates_ID list populated, although lazy loading is set to true for the EF model (edmx file). Is it possible to configure EntitiesToDTOs to support lazy loading of child elements or will it always use eager loading? I can't see any option in EntitiesToDTOs that could be set to support lazy loading when generating the assembler.
By the way, I'm part of a larger team that uses EntitiesToDTOs to regenerate the assemblers on an almost daily basis, so I'd prefer not to modify the assembler by hand if possible.
I'm Fabian, creator of EntitiesToDTOs.
First of all, thanks a lot for using it.
What you have detected is in fact what I don't want the Assembler to do, I want the developer to map the navigation properties only if needed using the partial methods OnDTO and OnEntity. Otherwise you run into problems like you have.
Seems like I never run into that problem using the tool, THANKS A LOT.
So right now I'm fixing this. It's now fixed in version 3.1.
Based on the code that you've posted here, and based on how I think someone would implement such a solution (i.e. to convert records to a DTO format) I think that you would have no choice but to do eager loading.
Some key points:
1) Your Updates_ID field is clearly a List, which means that it's hydrating the collection right away (ToList always executes. Only a regular IEnumerable employs deferred execution).
2) If you're sticking any sort of navigation property in a DTO it would automatically be loaded eagerly. That's because once you so much as touch a navigation property that was brought back by Entity Framework, the framework automatically loads it from the database, and doesn't care that all you wanted was to populate a DTO with it.
I am using EF4, and I using the System.Data.Entity dll in my class. However, I can't see the load method of my navigation property of my entity.
How can I access to this method?
What I am doing is create e 4.0 project of .NET, create my edmx from a database, right click in the model edmx and I generate a DBContext.
However, I can access to the local property of my context, that I think that is a feature of EF4.
Thanks.
Daimroc.
For the DbContext approach, the IsLoaded property and Load method have been moved:
context.Entry(yourEntity)
.Collection(entity => entity.NavigationProperty)
.IsLoaded;
context.Entry(yourEntity)
.Collection(entity => entity.NavigationProperty)
.Load();
Entry method: http://msdn.microsoft.com/en-us/library/gg696578(v=vs.103).aspx
Collection method: http://msdn.microsoft.com/en-us/library/gg671324(v=vs.103).aspx
IsLoaded property: http://msdn.microsoft.com/en-us/library/gg696146(v=vs.103).aspx
Load method: http://msdn.microsoft.com/en-us/library/gg696220(v=vs.103).aspx
When you write the query (all this also works with lambda syntax as well btw)
From a in context.EntitySet.Include("Navigation Property NAme")
select a
and all will be there ;) .. or more to the point the navigation properties will be populated.
can be wierd with lots of joins though
you can also
From a in context.EntitySet.Include("Navigation1.Navigation2.Navigation2")
.Include("SomeOtherNavigation")
select a
where navigation1 and SomeOtherNavigation are navigation properties on the entity set
Failing that you can turn on lazy loading in the context. But its evil imo.
Also it doesnt really scale well when you go for an SOA approach as you need to include prior to knowing about the lazy load in your repository.
Ie you run the query in your repository, send stuff over the service and then want the navigation properties in the front end ... by which time its too late to lazy load ... EG you are using a wcf service that doesn't use data services.
Important to note that you ahve to use Include on the EntitySet, it is not on an IQueryable<>.
A real example:
var csg = from ucsg in c.UserCarShareGroups.Include("UserCarShareGroups.User.UserVehicles")
where ucsg.User.UserName.ToLower() == userName.ToLower()
&& ucsg.CarShareGroup.Carpark.Name.ToLower().Equals(carparkName.ToLower())
&& ucsg.DeletedBy == null
select ucsg.CarShareGroup;
(the database has case sensitive collation for some reason)
An alternate approach (and maybe more relevant is here)
Entity Framework - Trouble with .Load()
However I like doing it the way I said because it is explicit and I know exactly what is being pulled out. Especially when dealing with large datasets.
An answer to a question that combines my concerns with Load() is here:
Entity Framework 4 load and include combine