linq entity framework include weird behaviour - linq

I have an issue with the linq query when I dont explicitly use include for a navigation property.
---Task entity model ----
...
public Project Project { get; set; }
public TaskType TaskType { get; set; }
...
var tasks = db.Tasks
.Where(t => (t.Project.ProjectId == project.ProjectId))
foreach (Task t in tasks)
{
// for some items t.TaskType is null
// I have noticed that when t.TaskType.Id
// is different to the first one in the loop then only the next different
// tasktype is null
}
// however when using
var tasks = db.Tasks.Include(t=>t.TaskType)
.Where(t => (t.Project.ProjectId == project.ProjectId))
// tasktype is always there (where as without the include in some tasks it does not extract the tasktype)
Using the .Include fixed my issue but I like to understand why it behaves like this.

If you use Eager Loading in EF, then navigation properties not load with root object. Include method instruct EF, that navigation property should loaded with your root object.
With Lazy loading your navigation property loaded, when you call this property, so if you use lazy load, then Include method not necessary.
More here

I think what you looking for is lazy load the related entities. To do that you need to specify your navigation properties as virtual. From this page:
Lazy loading is the process whereby an entity or collection of
entities is automatically loaded from the database the first time that
a property referring to the entity/entities is accessed. When using
POCO entity types, lazy loading is achieved by creating instances of
derived proxy types and then overriding virtual properties to add the
loading hook.
When you specify the virtual keyword in your navigation properties, EF creates at runtime dynamic proxies for your entity classes. Those proxy classes are responsible for the lazy loading behavior of the related entities. Without virtual, lazy loading will not be supported, and you get null on your navigation properties. So you need to do this:
public class Task
{
//...
public virtual Project Project { get; set; }
public virtual TaskType TaskType { get; set; }
{
In this link you will find all the requiriments you need to follow to support lazy loading.
Using the Include method you can eager load the related entities as part of the query.

Related

Web API is it necessary to have ViewModels layer classes?

When I use Web (MVC), I always to create a separate classes layer. These classes often the same as DTO classes, but with attributes like [Display(Name = "Street")] and validation. But for web api Display attributes are not necessary, validation can be used by FluentValidation. Should Api controller returns ViewModels classes or DTO classes will be fine too?
the answer, as always is .... it depends.
If your API is serving multiple clients , apps etc, then returning DTOs is a better options.
ViewModels are specific to the MVC client and should already be prepared for display, meaning the data should already be formatted in a specific way, some fields maybe combined, they should satisfy whatever requirements the display pages have. They are called ViewNodels for a reason. The point is that they are rarely exactly the same as the data the API returns, which should be a bit more generic and follow a certain pattern to make sense to its users.
If your ViewModels are exactly the same and you only have one client then it's up to you if you want to create a set of duplicated classed just to avoid having the attributes.
Mapping from DTO to ViewModel and viceversa is not exactly complicated, but the process does introduce one more complication, one more layer.
Don't forget one thing though. API DTOs are supposed to return the data they have on any entity regardless of the requirements of any UI. Requirements can change anyway, new fields added or discarded. You're more than likely to leave the API alone when that happens and simply change your ViewModels.
Your ViewModels are specific to a UI page and should contain only the data required by that page. This means that you can end up with multiple ViewModels for the same data, it's just that the display requirements are different for each.
My vote goes towards keeping the ViewModels and DTOs separate, even if, at this point in time they are exactly the same. Thins always change and this is one of those things you can actually be ready for.
Actually it depends on application's architecture how we want to return response. In this case yes we can return DTO classes but i think that would not be the good approach because we should create a separate Resource classes that will map with DTO and then return. Just see the below example:
public class CustomerDTO
{
public int ID { get; set; }
public string Name { get; set; }
public int DepartmentId { get; set; }
}
public class CustomerResource
{
[JsonObject]
public string Name { get; set; }
[JsonObject]
public string Department { get; set; }
}
Suppose we have CustomerDTO class and we want to return response in the following json format
{
"name":"Abc xyz",
"department":"Testing"
}
So in this case we should we have separate class that will return as a response to the end user as i created CustomerResource. In this scenario we will create a mapper that will map DTO with resource object.
And also with this implementation we can test resources independently

List vs IEnumerable vs IQueryable when defining Navigation property

I want to create a new model object named Movie_Type in my ASP.NET MVC web application. What will be the differences if I define the navigation proprty of this class to be either List, ICollection or IQueryable as following?
public partial class Movie_Type
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public List<Movie> Movies { get; set; }
}
OR
public partial class Movie_Type
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public IQueryable<Movie> Movies { get; set; }
}
OR
public partial class Movie_Type
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public ICollection<Movie> Movies { get; set; }
}
Edit:-
#Tomas Petricek.
thanks for your reply. in my case i am using the database first approach and then i use DbContext template to map my tables, which automatically created ICollection for all the navigation properties, So my questions are:-
1. Does this mean that it is not always the best choice to use Icollection. And i should change the automatically generated classes to best fit my case.
2. Secondly i can manage to choose between lazy or Eager loading by defining .include such as
var courses = db.Courses.Include(c => c.Department);
Regardless of what i am using to define the navigation properties. So i can not understand ur point.
3. i did not ever find any examples or tutorials that use IQuerable to define the navigation properties ,, so what might be the reason?
BR
You cannot use a navigation property of type IQueryable<T>. You must use ICollection<T> or some collection type which implements ICollection<T> - like List<T>. (IQueryable<T> does not implement ICollection<T>.)
The navigation property is simply an object or a collection of objects in memory or it is null or the collection is empty.
It is never loaded from the database when you load the parent object which contains the navigation property from the database.
You either have to explicitely say that you want to load the navigation property together with the parent which is eager loading:
var movieTypes = context.Movie_Types.Include(m => m.Movies).ToList();
// no option to filter or sort the movies collection here.
// It will always load the full collection into memory
Or it will be loaded by lazy loading (which is enabled by default if your navigation property is virtual):
var movieTypes = context.Movie_Types.ToList();
foreach (var mt in movieTypes)
{
// one new database query as soon as you access properties of mt.Movies
foreach (var m in mt.Movies)
{
Console.WriteLine(m.Title);
}
}
The last option is explicit loading which comes closest to your intention I guess:
var movieTypes = context.Movie_Types.ToList();
foreach (var mt in movieTypes)
{
IQueryable<Movie> mq = context.Entry(mt).Collection(m => m.Movies).Query();
// You can use this IQueryable now to apply more filters
// to the collection or sorting, for example:
mq.Where(m => m.Title.StartWith("A")) // filter by title
.OrderBy(m => m.PublishDate) // sort by date
.Take(10) // take only the first ten of result
.Load(); // populate now the nav. property
// again this was a database query
foreach (var m in mt.Movies) // contains only the filtered movies now
{
Console.WriteLine(m.Title);
}
}
There are two possible ways of looking at things:
Is the result stored in memory as part of the object instance?
If you choose ICollection, the result will be stored in memory - this may not be a good idea if the data set is very large or if you don't always need to get the data. On the other hand, when you store the data in memory, you will be able to modify the data set from your program.
Can you refine the query that gets sent to the SQL server?
This means that you would be able to use LINQ over the returned property and the additional LINQ operators would be translated to SQL - if you don't choose this option, additional LINQ processing will run in memory.
If you want to store data in memory, then you can use ICollection. If you want to be able to refine the query, then you need to use IQueryable. Here is a summary table:
| | Refine query | Don't change query |
|-----------------|--------------|--------------------|
| In-memory | N/A | ICollection |
| Lazy execution | IQueryable | IEnumerable |
More of a standard is IEnumerable as it is the least common denominator.
Iqueryable can be returned if you want extra querying functionality to the caller without having 10 repository methods to handle varying querying scenarios.
A downside is ienumerable could 'count()' slowly but if the object implements ICollection then this interface is checked for this value first without having to enumerate all items.
Also be aware if you return iqueryable to an untrusted caller they can do some casting and method calls on the iqueryable and get access to the context, connection, connection string, run queries, etc
Also note nhibernate for example has a query object you can pass to a repository to specify options. With entity framework you need to return IQueryable to enhance querying criteria
The collection that entity framework actually creates for you if you use virtual navigation properties implements ICollection, but not IQueryable, so you cannot use IQueryable for your navigation properties, as Slauma says.
You are free to define your properties as IEnumerable, as ICollection extends IEnumerable, but if you do this then you will lose your ability to add new child items to these navigation properties.

Model binding in the controller when form is posted - navigation properties are not loaded automatically

I'm using the Entity Framework version 4.2. There are two classes in my small test app:
public class TestParent
{
public int TestParentID { get; set; }
public string Name { get; set; }
public string Comment { get; set; }
public virtual ICollection<TestChild> TestChildren { get; set; }
}
public class TestChild
{
public int TestChildID { get; set; }
public int TestParentID { get; set; }
public string Name { get; set; }
public string Comment { get; set; }
public virtual TestParent TestParent { get; set; }
}
Populating objects with data from the database works well. So I can use testParent.TestChildren.OrderBy(tc => tc.Name).First().Name etc. in my code.
Then I built a standard edit form for my testParents. The controller look like this:
public class TestController : Controller
{
private EFDbTestParentRepository testParentRepository = new EFDbTestParentRepository();
private EFDbTestChildRepository testChildRepository = new EFDbTestChildRepository();
public ActionResult ListParents()
{
return View(testParentRepository.TestParents);
}
public ViewResult EditParent(int testParentID)
{
return View(testParentRepository.TestParents.First(tp => tp.TestParentID == testParentID));
}
[HttpPost]
public ActionResult EditParent(TestParent testParent)
{
if (ModelState.IsValid)
{
testParentRepository.SaveTestParent(testParent);
TempData["message"] = string.Format("Changes to test parents have been saved: {0} (ID = {1})",
testParent.Name,
testParent.TestParentID);
return RedirectToAction("ListParents");
}
// something wrong with the data values
return View(testParent);
}
}
When the form is posted back to the server the model binding appears to be working well - i.e. testParent looks okay (id, name and comment set as expected). However the navigation property TestChildren remains at NULL.
This I guess is not sooo surprising since the model binding merely extracts the form values as they were sent from the browser and pushes them into an object of the TestParent class. Populating testParent.TestChildren however requires an immediate roundtrip to the database which is the responsibility of the Entity Framework. And EF probably doesn't get involved in the binding process.
I was however expecting the lazy loading to kick in when I call testParent.TestChildren.First(). Instead that leads to an ArgumentNullException.
Is it necessary to tag an object in a special way after model binding so that the Entity Framework will do lazy loading? How can I achieve this?
Obviously I could manually retrieve the children with the second repository testChildRepository. But that (a) doesn't feel right and (b) leads to problems with the way my repositories are set up (each using their own DBContext - which is an issue that I haven't managed to come to terms with yet).
In order to get lazy loading for your child collection two requirements must be fulfilled:
The parent entity must be attached to an EF context
Your parent entity must be a lazy loading proxy
Both requirements are met if you load the parent entity from the database through a context (and your navigation properties are virtual to allow proxy creation).
If you don't load the entity from the database but create it manually you can achieve the same by using the appropriate EF functions:
var parent = context.TestParents.Create();
parent.TestParentID = 1;
context.TestParents.Attach(parent);
Using Create and not new is important here because it creates the required lazy loading proxy. You can then access the child collection and the children of parent with ID = 1 will be loaded lazily:
var children = parent.TestChildren; // no NullReferenceException
Now, the default modelbinder has no clue about those specific EF functions and will simply instantiate the parent with new and also doesn't attach it to any context. Both requirements are not fulfilled and lazy loading cannot work.
You could write your own model binder to create the instance with Create() but this is probably the worst solution as it would make your view layer very EF dependent.
If you need the child collection after model binding I would in this case load it via explicit loading:
// parent comes as parameter from POST action method
context.TestParents.Attach(parent);
context.Entry(parent).Collection(p => p.TestChildren).Load();
If your context and EF is hidden behind a repository you will need a new repository method for this, like:
void LoadNavigationCollection<TElement>(T entity,
Expression<Func<T, ICollection<TElement>>> navigationProperty)
where TElement : class
{
_context.Set<T>().Attach(entity);
_context.Entry(entity).Collection(navigationProperty).Load();
}
...where _context is a member of the repository class.
But the better way, as Darin mentioned, is to bind ViewModels and then map them to your entities as needed. Then you would have the option to instantiate the entities with Create().
One possibility is to use hidden fields inside the form that will store the values of the child collection:
#model TestParent
#using (Html.BegniForm())
{
... some input fields of the parent
#Html.EditorFor(x => x.TestChildren)
<button type="submit">OK</button>
}
and then have an editor template for the children containing the hidden fields (~/Views/Shared/EditorTemplates/TestChild.cshtml):
#model TestChild
#Html.HiddenFor(x => x.TestChildID)
#Html.HiddenFor(x => x.Name)
...
But since you are not following good practices here and are directly passing your domain models to the view instead of using view models you will have a problem with the recursive relationship you have between the children and parents. You might need to manually populate the parent for each children.
But a better way would be to query your database in the POST action and fetch the children that are associated to the given parent since the user cannot edit the children inside the view anyway.

How to use a Dictionary or Hashtable for LINQ query performance underneath an OData service

I am very new to OData (only started on it yesterday) so please excuse me if this question is too dumb :-)
I have built a test project as a Proof of Concept for migrating our current web services to OData. For this test project, I am using Reflection Providers to expose POCO classes via OData. These POCO classes come from in-memory cache. Below is the code so far:
public class DataSource
{
public IQueryable<Category> CategoryList
{
get
{
List<Category> categoryList = GetCategoryListFromCache();
return categoryList.AsQueryable();
}
}
// below method is only required to allow navigation
// from Category to Product via OData urls
// eg: OData.svc/CategoryList(1)/ProductList(2) and so on
public IQueryable<Category> ProductList
{
get
{
return null;
}
}
}
[DataServiceKeyAttribute("CategoryId")]
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public List<Product> ProductList { get; set; }
}
[DataServiceKeyAttribute("ProductId")]
public class Product
{
public int ProductId { get; set; }
public string ProductName { get; set; }
}
To the best of my knowledge, OData is going to use LINQ behind the scenes to query these in-memory objects, ie: List in this case if somebody navigates to OData.svc/CategoryList(1)/ProductList(2) and so on.
Here is the problem though: In the real world scenario, I am looking at over 18 million records inside the cache representing over 24 different entities.
The current production web services make very good use of .NET Dictionary and Hashtable collections to ensure very fast look ups and to avoid a lot of looping. So to get to a Product having ProductID 2 under Category having CategoryID 1, the current web services just do 2 look ups, ie: first one to locate the Category and the second one to locate the Product inside the Category. Something like a btree.
I wanted to know how could I follow a similar architecture with OData where I could tell OData and LINQ to use Dictionary or Hashtables for locating records rather than looping over a Generic List?
Is it possible using Reflection Providers or I am left with no other choice but to write my custom provider for OData?
Thanks in advance.
You will need to process expression trees, so you will need at least partial IQueryable implementation over the underlying LINQ to Objects. For this you don't need a full blown custom provider though, just return you IQueryable from the propties on the context class.
In that IQueryable you would have to recognize filters on the "key" properties (.Where(p => p.ProductID = 2)) and translate that into a dictionary/hashtable lookup. Then you can use LINQ to objects to process the rest of the query.
But if the client issues a query with filter which doesn't touch the key property, it will end up doing a full scan. Although, your custom IQueryable could detect that and fail such query if you choose so.

Beginner EF4 / CodeFirst / MVC3 help

Although I love what I'm learning, I'm finding it a struggle and need some help
I've been using these two tutorials which I think are awesome:
http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx
http://msdn.microsoft.com/en-us/data/gg685467
Currently my main problem/confusion is:
I have a CodeFirst table/entity I don't know how to correctly get data from other tables/entities to show in my views:
public class Car {
public int ID { get; set; }
public string Name { get; set; }
public int EngineID { get; set; }
public virtual Engine { get; set; }
}
public class Engine {
public int ID { get; set; }
public string Name { get; set; }
public string Manufacturer { get; set; }
// (plus a whole lot of other things)
}
Now when I create a View for Cars (using the List type/option) I get a nice autogenerated list
#foreach (var item in Model) {
<tr>
<td>#item.ID</td>
<td>#item.Name</td>
<td>#item.EngineID</td>
</tr>
Perfect... except EngineID is mostly worthless to the viewer, and I want to show Engine.Name instead
So I assumed I could use EF lazy loading:
<td>#item.Engine.Name</td>
Unfortunately when I tried that, it says my ObjectContext has been disposed so can't get any further data requiring a connection
Then I tried going to the controller and including the Engine.Name
var cars = (from c in db.Cars.Include("Engine.Name") select c;
Which tells me: Entities.Engine does not declare a navigation property with the name 'Name'
... ? Lies
Include("Engine") works fine, but all I want is the Name, and Include("Engine") is loading a large amount of things I don't want
Previously in a situation like this I have created a view in the DB for Car that includes EngineName as well. But with CodeFirst and my noobness I haven't found a way to do this
How should I be resolving this issue?
I thought perhaps I could create a Model pretty much identical to the Car entity, but add Engine.Name to it. This would be nice as I could then reuse it in multiple places, but I am at a loss on how to populate it etc
Wanting to learn TDD as well but the above is already frustrating me :p
Ps any other tutorial links or handy things to read will be greatly appreciated
It isn't lies as you are actually trying to include a property that's a 2nd level down withouth giving it a way to navigate. If you let EF generate your DB with this structure, it would likely have made a navigation table called something like Car_Engine and if you include the name without the object it HAS mapped, then it's not got a navigation property in your new object.
The simple way around this is to go:
(from c in db.Cars.Include("Engine") select new { c, EngineName = c.Engine.Name }
If you still get navigation property errors then you might need to make sure your are mapping to your schema correctly. This can be done with EntityTypeConfiguration classes using the fluent API - very powerful.
This of course won't help in strongly typing your car object to show in MVC.
If you'd like to get around this, your gut feeling is right. It's pretty common to use viewmodels that are read only (by design, not necessarily set to readonly) classes that provide simple views of your data.
Personally I keep my model quite clean and then have another project with viewmodels and a presentation project to populate. I'd avoid using overlapping entities in your core model as it might lead to unpredictable behaviour in the data context and at least a peristance nightmare when updating multiple entities (ie who's responsible for updating the engine name?).
Using you viewmodels, you can have a class called CarSummaryView or something with only the data you want on it. This also solves the issue of being vulnerable to overposting or underposting on your site. It can be populated by the above query quite easily.
PS There's a bunch of advantages to using viewmodels beyond just not loading full heirarchies. One of the biggest is the intrinsic benefit it gives you with avoiding over and underposting scenarios.
There's loads of ways to implement viewmodels, but as a simple CarView example:
public class CarView
{
public int ID { get; set; }
public string Name { get; set; }
public string EngineName { get; set; }
}
This should be clearly seperated from your entity model. In a big project, you'd have a single viewmodels project that the presenter can return, but in a smaller one you just need them in the same layer as the service code.
To populate it directly from the query, you can do the following
List<CarView> cars = (from c in db.Cars.Include("Engine.Name") select new CarView() { ID = c.ID, Name = c.Name, EngineName = c.Engine.Name }).ToList();

Resources