There are hundreds of examples of loading Entity Framework objects with the include statement but they stop short of Great GrandChild objects.
I have a complex object linked to about 48 tables, some of which go beyond the simple parent.child.grandchild code provided. Specifically I have a pattern object with a child entities that holds address entities that holds address field entities. (Among other entities it is holding.)
Here is the usual solution to the address grand child:
context.StagingPatternSet.Include( sp => sp.StagingPatternEntities.Select( e => e.StagingPatternAddresses ).ToList();
but how does one add the StagingPatternAddressFields to the list which is child to StagingPatternAddresses. Linq has nothing to add beyond the first select that I can find.
Linq to SQL has a wonderful extension that lets me define it with the DataLoadOptions...
var dlo = new DataLoadOptions();
dlo.LoadWith<StagingPattern>( p => p.StagingPatternEntities );
dlo.LoadWith<StagingPatternEntity>( e => e.StagingPatternAddresses );
dlo.LoadWith<StagingPatternAddress>( a => a.StagingPatternAddressFields );
but alas, this is not available to context DbSets. You set it to the LoadOptions of your SQL db. I would most appreciate if anyone has an elegant solution to this problem.
Kent
Related
I am using 10+ (depending of use case) calls to database, just to populate dropdown lists in my view.
Like in the code shown here:
ViewBag.FK_Grupe_Predmeta_ID = new SelectList(db.Get_Grupe_Predmeta(userLanguageID).ToList(), "ID", "Naziv");
ViewBag.FK_Klasifikacione_Oznake_ID = new SelectList(db.Get_Klasifikacione_Oznake(userLanguageID).ToList(), "ID", "Naziv");
ViewBag.FK_Stranke_ID = new SelectList(db.Strankes.Where(s => s.Povjerljiv == true), "ID", "Naziv");
ViewBag.FK_Prioriteti_ID = new SelectList(db.Get_Prioriteti(userLanguageID).ToList(), "ID", "Naziv");
ViewBag.odjeljenja = new SelectList(db.Get_Odjeljenja(userLanguageID).OrderBy(x => x.Naziv).ToList(), "ID", "Naziv");
ViewBag.VrstePostupka = new SelectList(db.Vrsta_Postupkas.ToList(), "PK_Vrsta_Postupka_ID", "Naziv_Vrste_Postupka");
I call stored procedures and tables. But when I test with multiple users in same time, I get long loading time, sometimes in the minutes.
Can't find any way to make less calls and populate ViewBag in same time.
Does anyone know what is the best approach in this situation?
Thanks
One suggestion rather than passing entire entity sets to the SelectList constructor would be to just send a projection of the fields needed. I'd probably avoid calling Stored Procedures unless absolutely necessary and let EF interact with the tables to build optimal queries.
var strankes = db.Stranks
.Where(x => x.Povjerljiv)
.Select(x => new { x.ID, x.Naziv });
ViewBag.FK_Stranke_ID = new SelectList(stranks, "ID", "Naziv");
For common lookups, you can project to a view model for the ID and Name(Naziv) and then consider caching those to session to avoid re-loading them every time the page loads. Your SelectList gets built from the cached view models rather than hitting the DB again.
Make sure your DbContext lifetime scope is set no longer than per-request. DbContexts that have been alive longer and tracking far more entities over time become a lot slower for retrieving and updating entities. The more it is tracking, the more cached entities it will be sifting through when you ask for something, then going to the DB to read more entities, then stitching those resulting entities against it's local cache. (for populating any related entities, etc.) For maximum performance when loading sets fast, consider a bounded context with a minimum of navigation properties between lookup entities (mapping just FK columns) and read via a locally scoped bounded DbContext.
Other performance pitfalls to watch out for are any places where entities might be serialized and sent to the view. Entities that have navigation properties to lookups etc. that get "touched" by a serializer can end up triggering lazy loading to load each related entity one level at a time. My recommendation is always to project entities down to ViewModels to send to the view to avoid traps like this. Due to the queries lazy load traps can generate they can look a lot like cases where lookup queries are being triggered. An SQL Profiler can be very helpful for spotting situations where a lot of queries are being generated unexpectedly as a page loads.
I am developing MVC application and using razor syntax. I have used model first method.
I have two entities, Customer and Lead. Lead is inherited from Customer.
When IsActive property is true then Customer treated as a Lead, otherwise it will be a customer.
Please check edmx file image.
Now, In regular entities we just deal with single entity and single table.
In this case how can I handle , Save and Load process. beacuse I have to store and load the record from 2 tables of DB.
Is Regular Index View will work here ?
When using inheritance in the Entity Framework you will have a single DbSet on your DbContext that exposes your hierarchy. In your database you have several options for configuring your table structure. For example you can use:
Table per Hierarchy
Table per Type
Table per Concrete type
(See this blog for a nice explanation: Inheritance in the Entity Framework.
In your queries however, you don't have to think about this. Your queries will have the following structure:
var leads = from l in dbcontext.Leads.OfType<Customer>()
select l;
The OfType() filters your collection to a subtype in your hierarchy. If you skip the OfType you will get both customers and leads in your resulting query.
I am constanstly having problems with model design in MVC. Mostly all of my projects require some entities that are to be created, edited and deleted. Most of these entities have some common properties like creation date, modified date, author, modified by and in some cases even more descriptive properties are common. Because of that I have one single DB table to store them. For instance, Documents table and we store Invoices, Quotations and other business documents in it. I am using Entity Framework v4 for ORM, where we eventually end up with the Document entity.
How do I modify this entity or do I create a separate DocumentViewModel class for it to support multiple document types with common properties (so some form of inheritance or interface implementation should be implemented)? Besides identifying different document types I also need to have some types to have different Data Annotation rules (attributes).
For instance, Document table has PayDate column. Document type Invoice requires PayDate to be provided but document type Quotation does not.
This is the one single problem I am facing over and over with MVC and so far I've been handling it different every time but cannot decide how to properly handle it to achieve the maximum application maintainability and ease of development.
Have you considered making Documents entity abstract?
From the DB side, you will have Documents table containing just the fields shared by all Invoices/Quoations/etc. This field will have an IDENTITY PK - e.g DocId.
In the other tables, additional meta-data specific to that document can be stored, and the PK is a (non-IDENTITY) field DocId, which is also a FK to the Documents table.
On the EF side, Documents becomes an abstract entity, and the other entities inherit from this entity. This allows a nice OO paradigm to exist, and makes your code more robust.
We are currently using this scheme (EF4/SQL Server).
Your scenario sounds very similar to ours - consider using Abstract Classes.
EDIT
Thought i'd add a bit more info to how i've actually implemented this scenario, to put you on the right track.
As the comments to your Q state, we have little knowledge of your domain, therefore it's hard to make informed opinions. Personally, i chose to make my entity abstract, because certain functionality required a "mixed-bag" of items to be returned in one hit. There are other ways to do this of course (such as a stored procedure), but this allows a nice fluent interface between my UI (which is MVC by the way) and my service layer.
Works like this - here's how i get a single Post:
// var is strongly-typed to a "Post"
var somePost = repository.FindSingle(10);
Here's how i get a mixed-bag of Posts:
// var is strongly-typed to a "ICollection<Post>".
// "Title" is a property on my "Post" abstract POCO
var mixedBagOfPosts = repository.FindAll<Post>(p => p.Title = "Some Title");
Here's how i get a collection of "Reviews" (child of Post):
// var is strongly-typed to a "ICollection<Review>"
// "Rating" is a property on my "Review" POCO (derived from Post)
var reviews = repository.FindAll<Review>(r => r.Rating == 5.00);
The kicker is my repository is implemented with generics, and the type parameter ensures type-safety:
ICollection<T> FindAll<T>(Expression<Func<T,bool>> predicate) where T : Post
And it's implemented like this:
return myContext.Posts.OfType<T>.Where(predicate).ToList();
The OfType causes an inner join to the T (which is the child table), so only those records are returned.
Of course, i also have a service layer mediating between my UI and repository, but this should get you on the right track.
Also, you don't have to go with the whole Expression-predicate thing, i like this because it minimizes the number of methods on my interface, and gives full querying power to my controllers, whilst ensuring the queries are deferred to the point of the service layer, but not further.
If you don't like this, you could of course have regular parameters (string title, etc).
As i said, this architecture suited my domain requirements, so it may not necessarily suit yours, but hopefully it gives you some insight.
You can put a table in your EF model many times and just rename them to the entities you need. Just delete the columns you dont need from those.
For example, put in a Documents entity... now rename it to Invoice. Now add another one, and name it Quotation... on the Quotation, click on PayDate and hit the delete key. You can customize these all you want! You can do the same with other ORMs, just takes a little more work. With NHibernate you would manually create the Models, then map them to the same table, but only map what you need.
I have a few tables that reference the same table. For example:
Person has an address.
Business has an address.
When using the models I would like to do this in the controller:
person.Address.Zip
business.Address.Zip
I'm coming from a rails background where I can just declare a relationship and have all the above functionality. Force loading of the address when I get the object (person or business).
I'm new to entity framework, and I'm struggling with how to achieve that functionality. I can't include the table in both models (person and business). If I use repository pattern and add the objects to a partial for the class, then I'm using lazy loading.
Am I looking at this wrong? Any suggestions for patterns I could use?
If your using Entity Framework 4.0 with Visual Studio 2010 lazy loading is automatic.
If your using Entity Framework 1.0 your life just got harder...
To eager load with EF1 you have to use the Include() method on your ObjectQuery and specify which navigation properties ( address ). For example:
ModelContainer.Persons.Where(#p => #p.Id == 39 ).Include("Address")
For "lazy" loading you have to manually load all of the FK associations manually. For example:
var myPeople = ModelContainer.Persons.Where(#p => #p.Id == 39
if( !myPeople.Address.IsLoaded() )
myPeople.Address.Load()
Another option is to modify how EF1 generates your model types and include lazy loading out of gates.
http://code.msdn.microsoft.com/EFLazyLoading
Previously, I was creating an ADO.NET Entity Data Model for each controller.
Now I've created one Data Model for all tables (it's not a monstrous db). That way I can include the tables when I query for eager loading.
If anyone has a better suggestion. Let me know. If anyone knows the correct behavior with a large database, please comment. Would you want one large edmx file to represent the database?
Ideally you should be able to traverse the object model to get most of the data you need, starting with a reference to the current user object.
I've recently started playing around with the ASP.NET MVC NerdDinner sample, and as part of that you get to play around with Linq to SQL classes. This looks cool, so I decided to break away (perhaps a tad prematurely!) and try and create my own MVC application, but this time modelling my own simple database with Linq to SQL.
The problem I'm having is this. Consider these tables:
Car
Person
Passengers
The table CarPassengers is a mapping table between Car and Person (it has two columns: CarId, PersonId).
In Linq to SQL, I get a class for every table. But, what I really want is a class for Car that has the property CarPassengers, with each child being a Person, rather than the actual FK's (it's ok for selecting results, but to update Car with new Person objects, I have to first construct them - I can't just add an EntitySet of CarPassengers without first instantiating the child Person objects, I think).
I've been looking around and I've seen that the ADO.NET Entity Framework will allow me to achieve this using Entity Splitting, but I wondered if there's an easy way to accomplish the same thing in Linq to SQL, and if not, what the affects are in terms of integrating the .NET EF with my MVC app.
Any advice, comments, tips would be much appreciated.
Thank you!
If you define the FKs prior to adding them to the designer surface you will get the EntitySets added to the class in a manner close to what you expect. CarPassengers will exist but it will be an EntitySet of CarPassenger objects, not Persons. Those objects, however, will have an associated Person EntityRef. This will allow you to find the passengers in the car.
var car = db.Car.Where( c => c.CarId == id );
var passengers = db.Car.CarPassengers.Select( cp => cp.Person );
Adding new passengers works as well, but also involves another step.
var car = db.Car.Where( c => c.CarId == id );
var person = new Person { ... };
car.CarPassengers.Add( new CarPassenger { Person = person } );
If you don't have the FK relationships defined ahead of time, you can always add the associations manually in the designer. MSDN has a HowTo article on this topic.