Finding Entity Framework contexts - entity-framework

Through various questions I have asked here and other forums, I have come to the conclusion that I have no idea what I'm doing when it comes to the generated entity context objects in Entity Framework.
As background, I have a ton of experience using LLBLGen Pro, and Entity Framework is about three weeks old to me.
Lets say I have a context called "myContext". There is a table/entity called Employee in my model, so I now have a myContext.Employees. I assume this to mean that this property represents the set of Employee entities in my context. However, I assume wrong, as I can add a new entity to the context with:
myContext.Employees.AddObject(new Employee());
and this new Employee entity appears nowhere in myContext.Employees. From what I gather, the only way to find this newly added entity is to track it down hiding in the myContext.ObjectStateManager. This sounds to me like the myContext.Employees set is in fact not the set of Employee entities in the context, but rather some kind of representation of the Employee entities that exist in the database.
To add further to this confusion, Lets say I am looking at a single Employee entity. There is a Project entity that has a M:1 relationship with Employee (an employee can have multiple projects). If I want to add a new project to a particular employee, I just do:
myEmployee.Projects.Add(new Project());
Great, this actually adds the Project to the collection as I would expect. But this flies right in the face of how the ObjectSet properties off of the context work. If I add a new Project to the context with:
myContext.Projects.AddObject(new Project());
this does not alter the Projects set.
I would appreciate it very much if someone were to explain this to me. Also, I really want a collection of all the Employees (or Projects) in the context, and I want it available as a property of the context. Is this possible with EF?

An ObjectSet is a query. Like everything in LINQ, it's lazy. It does nothing until you either enumerate it or call a method like .Count(), at which point a database query is run, and any returned entities are merged with those already in the context.
So you can do something like:
var activeEmployees = Context.Employees.Where(e => e.IsActive)
...without running a query.
You can further compose this:
var orderedEmployees = activeEmployees.OrderBy(e => e.Name);
...again, without running a query.
But if you look into the set:
var first = orderedEmployees.First();
...then a DB query is run. This is common to all LINQ.
If you want to enumerate entities already in the context, you need to look towards the ObjectStateManager, instead. So for Employees, you can do:
var states = EntityState.Added || EntityState.Deleted || // whatever you need
var emps = Context.ObjectStateManager.GetObjectStateEntries(states)
.Select(e => e.Entity)
.OfType<Employee>();
Note that although this works, it is not a way that I would recommend working. Typically, you do not want your ObjectContexts to be long-lived. For this, and other reasons, they are not really suitable to be a general-purpose container of objects. Use the usual List types for that. It is more accurate to think of an ObjectContext as a unit of work. Typically, in a unit of work you already know which instances you are working with.

Related

Entity Framework Save with Children

We have recently decided to use EF6 code first in one of our projects so I am undergoing a paradigm change. I really enjoy EF but some things are so different they seem wrong.
I just want to run a scenario by the community to see if I am thinking correctly.
We have an entity that has child entities of the same type.
If I was saving a child normally I would just save a new entity with the parent id set to the id of the parent. In the entity world they are connected through a navigation property of the same type as follows:
public class SomeType
{
public id;
....
public virtual IList<SomeType> Children
}
Obviously the standard approach doesn't work here since I am not manipulating DB foreign keys manually.
It seems the "Entity Way" would be to first use DBCcontext and linq to select the parent, then add the new entity to the Children list and save the whole thing.
Which is fine and logical - but it just seems a little inefficient to do a select every time i am doing a save.
Am I really missing something here do I just need to get used to a different way of thinking here?
Thank you!
If I'm getting your problem right, then you can and should save the child as a simple Sometype with a parentId, just as you would without using the entity framework. The automagic of the EF shouldn't cause a problem for you here, and you would not be breaking any best practices.
Essentially: If the parent entity is already loaded into context, it's usually best to add the new entity to the collection of navigation properties (Children in your case, but any foreign key). If the parent is not loaded and you know it's id, populate the foreign key field and save it just as you always did.

copy records from between two databases using EF

I need to copy data from one database to another with EF. E.g. I have the following table relations: Forms->FormVersions->FormLayouts... We have different forms in both databases and we want to collect them to one DB. Basically I want to load Form object recursively from one DB and save it to another DB with all his references. Also I need to change IDs of the object and related objects if there are exists objects with the same ID in the second database.
Until now I have following code:
Form form = null;
using (var context = new FormEntities())
{
form = (from f in context.Forms
join fv in context.FormVersions on f.ID equals fv.FormID
where f.ID == 56
select f).First();
}
var context1 = new FormEntities("name=FormEntities1");
context1.AddObject("Forms", form);
context1.SaveChanges();
I'm receiving the error: "The EntityKey property can only be set when the current value of the property is null."
Can you help with implementation?
The simplest solution would be create copy of your Form (new object) and add that new object. Otherwise you can try:
Call context.Detach(form)
Set form's EntityKey to null
Call context1.AddObject(form)
I would first second E.J.'s answer. Assuming though that you are going to use Entity Framework, one of the main problem areas that you will face is relationship management. Your code should use the Include method to ensure that related objects are included in the results of a select operation. The join that you have will not have this effect.
http://msdn.microsoft.com/en-us/library/bb738708.aspx
Further, detaching an object will not automatically detach the related objects. You can detach them in the same way however the problem here is that as each object is detached, the relationships that it held to other objects within the context are broken.
Manually restoring the relationships may be an option for you however it may be worthwhile looking at EntityGraph. This framework allows you to define object graphs and then perform operations such as detach upon them. The entire graph is detached in a single operation with its relationships intact.
My experience with this framework has been in relation to RIA Services and Silverlight however I believe that these operations are also supported in .Net.
http://riaservicescontrib.codeplex.com/wikipage?title=EntityGraphs
Edit1: I just checked the EntityGraph docs and see that DetachEntityGraph is in the RIA specific layer which unfortunately rules it out as an option for you.
Edit2: Alex Jame's answer to the following question is a solution to your problem. Don't load the objects into the context to begin with - use the notracking option. That way you don't need to detach them which is what causes the problem.
Entity Framework - Detach and keep related object graph
If you are only doing a few records, Ladislav's suggestion will probably work, but if you are moving lots of data, you should/could consider doing this move in a stored procedure. The entire operation can be done at the server, with no need to move objects from the db server, to your front end and then back again. A single SP call would do it all.
The performance will be a lot better which may or may not not matter in your case.

when using code first, accessing association does not account for .Take(x)

2 entities: Member and Comment
Member has an ICollection<Comment> Comments
Whenever I use member.Comments.Take(x) EF produces a query that gets all the comments from database.
Is it supposed to be like that?
Is it because property is ICollection?
Is there a way to tell EF to factor in my Take(x) or should i refactor my code to use context.Comments.Where(c=>c.MemberId==member.Id).Take(x) and live with it?
As described by #J. Tihon it is how EF works. When accessing lazy loaded property EF will always load the whole collection and any Linq expression is evaluated on the loaded collection. If you want to avoid that you must use the query as you described but the result of the query will not be loaded into your navigation property. To solve this you can use explicit loading instead of lazy loading:
context.Entry(member)
.Collection(m => m.Comments)
.Query()
.OrderBy(...) // Take requires some sorting
.Take(2)
.Load();
This should fill your Comments property with two comments.
The proxy classes generated by EF only provide lazy-loading for navigation properties, but they do not evaluate queries. Once you accessed the member.Comments property, the Comment-entities are loaded from the database and your query is applied in memory. To avoid this, you must get your comments in a query that is directly executed on the object-set (like the example you've already gave).
I believe this is by design, since you would have to return an IQueryable from the navigation property in order for the EF to intercept access to this property, but I suppose this isn't covered aswell.
You've already described a way to handle this, although it isn't pretty. Another option would be to somehow tell EF to partially load the property when you make the original query for the Member-object. I will look into that, but I can already think of one or two thinks that might go wrong with that approach.
Edit
After some research and trial and error I couldn't come up with another approach, that could be executed directly on the DbSet<Member> rather than DbSet<Comment> and returns a Member object. I is possible using an anonymous object:
var query = from m in catalog.Members
select new
{
Id = m.Id,
Name = m.Name,
Comments = m.Comments.Take(1)
};
Which could then be translated into a Member-object in memory, but of course it wouldn't be connected to the context in anyway (=no change tracking). In the sample query above I cannot create an instance of Member instead of an anonymous type, because EF can only create non-complex types (I'm guessing because the context knows that "Member" is an entity).

Using Entity Framework navigation properties without creating lots of queries (avoiding N+1)

I've been using Entity Framework Profiler to test my data access in an MVC project and have come accross several pages where I'm making far more db queries than I need to because of N+1 problems.
Here is a simple example to show my problem:
var club = this.ActiveClub; // ActiveClub uses code similar to context.Clubs.First()
var members = club.Members.ToList();
return View("MembersWithAddress", members);
The view loops through Members and then follows a navigion property on each member to also show their address. Each of the address requests results in an extra db query.
One way to solve this would be to use Include to make sure the extra tables I need are queried up front. However, I only seem to be able to do this on the ObjectSet of Clubs attached directly to the context. In this case the ActiveClub property is shared by lots of controllers and I don't always want to query the Member and address table up front.
I'd like to be able to use something like:
var members = club.Members.Include("Address").ToList();
But, Members is an EntityCollection and that doesn't have the Include method on it.
Is there a way to force a load on the Members EntityCollection and ask EF to also load their Addresses?
Or, is using EntityCollection navigation properties on an entity in this way, just a really bad idea; and you should know what you're loading when you get it from the context?
If your entities inherits from EntityObject try to use this:
var members = club.Members.CreateSourceQuery()
.Include("Address")
.ToList();
If you use POCOs with lazy loading proxies try to use this:
var members = ((EntityCollection<Club>)club.Members).CreateSourceQuery()
.Include("Address")
.ToList();
Obviously second version is not very nice because POCOs are used to remove dependency on EF but now you need to convert the collection to EF class. Another problem is that the query will be executed twice. Lazy loading will trigger for Members once to access the property and then second query will be executed when you call ToList. This can be solved by turning off lazy loading prior to running the query.
When you say ActiveClub is shared I believe it means something like it is property in base controller used in derived controllers. In such case you can still use different code in different controller to fill the property.

Inheritance problems with Entity Framework (table per type)

For part of the project I'm currently working on, I have a set of four tables for syndicatable actions. One table is the abstract base for the other three, and each table is represented in my EF model like so:
EF Model -- Actions http://chris.charabaruk.com/system/files/images/EF+Model+Actions.png
There are two problems that I'm currently facing with this, however. The first problem is that Actor (a reference to a User) and Subject (a reference to an entity of the class associated with each type of action) are null in my subclasses, despite the associated database columns holding valid keys to rows in their associated tables. While I can get the keys via ActorReference and SubjectReference this of course requires setting up a new EF context and querying it for the referenced objects (as FooReference.Value is also null).
The second problem is that the reciprocal end of the relationship between the concrete action classes and their related entity classes always turn up nothing. For example, Task.RelatedActions, which should give me all TaskAction objects where Subject refers to the particular task object on which RelatedActions is called, is entirely devoid of objects. Again, valid rows exist in the database, Entity Framework just isn't putting them in objects and handing them to me.
Anyone know what it is I'm doing wrong, and what I should do to make it work?
Update: Seems that none of the relationship properties are working in my entity model any more, at all. WTF...
I think the issue you are experiencing here is that by default the EF does not automatically load related entities. If you load an entity, the collection or reference to related entities will be empty unless you do one of the following things:
1) Use eager loading in order to retrieve your main entity and your related entity in a single query. To do this, modify your query by adding a call to the Include method. In your sample above, you might use the following query:
from a in context.Actions.Include("Actor") select a
This would retrieve each of the actions with the related Actor method.
2) Use explicit lazy loading to retrieve the related entity when you need it:
action1.ActorReference.Load()
In the version of the EF which will ship with .Net 4.0, you will also have the following additional option:
3) Turn on implicit lazy loading so that related entities will automatically be retrieved when you reference the navigation property.
Danny