Linq Projection is not including all data from the original entity - linq

I have encountered a LINQ issue and hope that you can help me to figure it out.
Here is what is happening.
I get an IQueryable<LicenseEntity> of entities from the repository.
I look at the fields in these entities and see that they contain valid data. There is a field for a related entity Customer in the LicenseEntity. It contains valid data, too, because I loaded it with the LicenseEntity.
I use .Select to project each LicenseEntity to a LicenseViewModel.
For each LicenseEntity, a LicenseEntity is passed into AutoMapper.Mapper.Map and is loaded into a LicenceViewModel entity.
After all of the entities have been processed, when I look at the list of LicenseViewModels in the debugger, it reports a null reference exception and there are no items to view.
To determine whether AutoMapper what causing my problem, I replaced it with a MapMe(). When I stopped at the return statement in MapMe and looked at the s parameter, which is the original entity, I found that the data in it is okay except that the customer field is now null. I assume that Select has done something that I don't know about.
How I can make Select retain all of the information in the original entity when it is doing its projection? Our solution cannot materialize the list because it may be very, very large. I've included my test code below and would really appreciate your help.
// Get the IQueryable<LicenseEntity> list of licenses from the repository.
var list = LicenseRepository.List();
// Convert the IQueryable<LicenseEntity> to an IQueryable<LicenseViewModel>
var vmlist = list.Select(x => MapMe(x, new LicenseViewModel()));
//var vmlist = list.Select(x => AutoMapper.Mapper.Map(x, new LicenseViewModel()));
// This function was used to see the LicenseEntity that was passing into Map().
// I discovered that the entity has all the correct data except for a related
// entity field, which was present in the original LicenseEntity before
public LicenseViewModel MapMe(LicenseEntity s, LicenseViewModel d)
{
return d;
}
The following code works properly however it materializes the entities, which we cannot do.
List<LicenseViewModel> vms = new List<LicenseViewModel>();
foreach (var item in list)
{
var vm = AutoMapper.Mapper.Map(item, new LicenseViewModel());
vms.Add(vm);
}

You've tagged this LINQ-to-Entities but there's no mention of the underlying technology in the text. But it's very likely that the problem is caused by lazy loading of associated objects.
This is a design choice that applies to most ORMs that I've worked with. When you load an object, connected objects are not loaded by default. If they were loaded by default it's quite clear you'd quickly break everything
when you load a Licence, the related Customer is automatically loaded
when the Customer is loaded all related objects are loaded - Company, Address, all other Licences, etc
for each of those objects, every related object is loaded...
The answer is that you need to specify which related objects to load. In the Entity Framework you do this using the Include method.
Because you are using a repository abstraction you might find this more difficult than it needs to be, but without knowing more I can't give any advice. This type of functionality - pretty basic stuff - is always a difficulty with repositories and 'unit-of-work' patterns.

I think your mapping should be more like:
var vms = Mapper.Map<List<LicenseEntity>, List<LicenseViewModel>>(list);
(ie - you don't need the foreach loop).
But unfortunately I doubt very much that that'll fix your issue as I suspect that'll also materialize your entities.

I've found the solution for projecting domain entities to viewmodels. If you are struggling with the same kind of issue as I had, please review the following links:
http://lostechies.com/jimmybogard/2011/02/09/autoprojecting-linq-queries/
http://www.devtrends.co.uk/blog/stop-using-automapper-in-your-data-access-code
By the way, in one one my domain entities, I had a partial class with some "calculated" properties... Properties whose values were generated from other fields in the database record. These cannot be in the domain entity because they will interfere with the aforementioned solutions. I moved them to my ViewModel class, which is where they were really required, and all is well.
Hope that this info helps...
Mike

Related

Durandal: Accessing one view model from another

Using Durandal, I have two view models within my app, let's say vmCompanies & vmEmployees. I have two views, one for each view model and within each, you can see all companies & all employees.
However, when I'm loading my employees, in the DB they have an ID for which company they are employed by. What I'd like to do is the following pseudo:
From within the vmEmployees, get a reference to the vmCompanies
If the vmCompanies has already been initialized (which I know it is 99% of the time), get a reference to it so I can use something like linq.js to find the specific company this employee works for
If the vmCompanies has not been initialized (aka: activated), do so
This way I can avoid the requirement of the vmEmployees having it's own internal cache of companies. So far I've been unable to figure out how in Durandal to query and ask "give me this view model that you've already loaded." It seems like it has that internally because when I navigate between views, they are cached and not reloaded (same with the VMs)... I've just so far been unable to see how I can do it.
You can manually require() a view model by its ____moduleId____. As long as your view model module returns an object and not a function, you'll be dealing with a singleton, so you can be sure you'll get the correct instance.
If you're not sure what the __moduleId__ is, you can use this chrome extension to view your view model's properties, including __moduleId__.
However, instead of manually instantianting VMs, a better alternative may be to create a separate module that you use to store the cached companies. I have a data module with its own internal cache that I use generically for this purpose, but you could create one specifically for companies, and store that information in it. It could even be responsible for loading its own data, if that's appropriate.
Here's some simple code to help explain:
Note this uses the sugar syntax for require JS - if you're using the array-based syntax, you'll need to translate accordingly. I can help if needed.
//companies-cache.js
define(function(require){
//some auto-loading logic here, if you wish
var companies = ko.observableArray([]);
return {
companies: companies
};
});
//vmCompanies, vmEmployees
define(function(require){
var companiesCache = require("viewModels/companies-cache");
//additional properties for this specific VM
...
return {
companies: companiesCache.companies
};
});

Entity Framework 5 - Invalid column name - Reverse Engineer Code First

Using Entity Framework 5, Visual Studio 2010 with the Entity Framework Power Tools (Beta 2) extension.
Here is my database table structure:
I used the Reverse Engineer Code First function of the aforementioned extension, which generated the POCO classes and some 'mapping' files (not sure if that's the formal parlance) and a single DbContext-derived class. Other than the change I describe next, all of these generated classes are as-generated by the power tool.
In the Category.cs file, I added the following code to help flatten the object graph a bit:
private ICollection<Product> m_Products = null;
public ICollection<Product> Products
{
get
{
if (m_Products == null)
{
m_Products = new List<Product>();
foreach (var categoryProduct in CategoryProducts)
{
m_Products.Add(categoryProduct.Product);
}
}
return m_Products;
}
set { m_Products = value; }
}
I get the following exception, which I know must have something to do with the mappings, but I just can't quite figure this out.
Unhandled Exception: System.Data.EntityCommandExecutionException: An error occurred while
executing the command definition. See the inner exception for details.
---> System.Data.SqlClient.SqlException:
Invalid column name 'Category_CategoryId'.
If I need to post more information, such as the specifics of the mappings, just let me know and I'll do it. I wanted to keep this as short as possible, but I realize I've omitted some things that, for those unfamiliar with the code generated by the tool, may leave one wanting for more details.
You've added a navigation property to your model and so EF is trying to map that to your database. "Code First" means your code model defines your database schema.
Try adding the [NotMapped] attribute to your helper properties to tell EF to ignore them.
In case you've created DB scheme automatically and you are not using strategies like (DropDatabaseAlways/DropDatabaseIfModelChanges) - other words: you are really in Reverse Engineering, it seems that you have to manually add column "CategoryId" on "Category" table.
In case, you don't want to work with the property (I mean in DB), you can use Data Annotation [NotMapped] or Fluent API modelBuilder.Entity<Category>().Ignore(x=> x.CategoryId)
Finally it is possible that problem can be in mapping. I don't know whether you are using data annotations or Fluent API but EF may automatically looks for some db column (logical behavior derived from the model) and can not find it. In this case I recommend you make a revision of the mapping.
The OP already solved their problem, but I've had a similar error with a different solution. So here it is in case others need it:
I was missing a navigation property on one side of a 0..1 relationship between entities. Once I added an appropriate navigation property to the entity that was missing it, the problem was solved.
A bit more details: I had two entities with a 0..1 relationship using a FK. Entity A (parent) had a FK to Entity B (child). The child entity B had a navigation property to entity A, but A did not have a navigation property to B. After adding this, the problem was solved.

how to json seralize entity framework many to many relationships without circular reference

I have 3 tables in my database - Conference, ActivityTypes and a joining table ConferenceActivities. Each conference may have a zero or many standard activities and each activity may occur in zero or more conferences.
Conference (ConferenceID, ConferenceName)
ConferenceActivities (ConferenceID,ActivityTypeID)
ActivityTypes (ActivityTypeID, ActivityTypeDesc)
I used Entity framework over my existing database, with the .tt templates in a MVC3 app I generated a DbContext and the POCO objects, noting that it generates just two objects, ActivityType and Conference which is nice it seems to understand the intermediary table.
It also adds a collection of activities to my conference
public virtual ICollection<ActivityType> ActivityTypes { get; set; }
And a collection of Conferences to my Activity.
public virtual ICollection<Conference> Conferences { get; set; }
I would like to return using JSON an object matching a specific conference.. that includes the ActivityTypes. Some might described this object as 'shaped' or 'jagged' because it has a collection within it.
I'm using code like the following although I've tried many different variations incase I had the syntax wrong but I still get a runtime error about recursion.
public JsonResult GetConference(int conferenceId)
{
Conference x = context.Conferences.Include("ActivityTypes").FirstOrDefault<Conference>(i => i.EventID == eventId);
return Json(x, JsonRequestBehavior.AllowGet);
}
It doesn't seem to work 'out of the box' and I see a lot of Stack Overflow questions that seem to relate but despite trying numerous different approaches but all create an error about recursion or parameterless constructors.. I am starting to doubt whether this is even possible.
I have tried attaching [IgnoreDataMemberAttribute] or [ScriptIgnore] to different properties to stop it trying to serialise the recursive relationship (I think the form is irrelevant but when your desperate..) and I still get the same error.
I've tried this sort of approach which generates the parameterless error
var thing = from r in context.Conferences
select new
{
r.ConferenceID,
r.ConferenceName,
ActivityTypes = new List<ActivityType>(
(from c in r.ActivityTypes
select new ActivityType()
{
ActivityTypeDesc = c.ActivityTypeDesc,
ActivityTypeID = c.ActivityTypeID
}).Cast<ActivityType>())
};
return Json(thing, JsonRequestBehavior.AllowGet);
Another suggestion was to set the Lazy Loading Enabled property on the model to false.. which made no difference I still get the recursion error.
I've tried removing the Virtual keyword which I belive turns off the lazy loading.. and trying with .Include(..) but again no joy.
Another suggestion was to change the accessor from public to internal however that made no different to the serialization.
Somebody also suggested removing the collection of Conferences from the ActivityType class, not really what I want to do.. but doing that just produces an error `Schema specified is not valid.' anyway.
I am using I believe the latest version nuget and the associated EF, scaffolding and templates.
Is what I'm trying to achieve something that should work out of the box? If so what setting(s) could I be missing and if not, what is the best practise here - the only way I know I can make this work is to build up the object manually myself.
Suggestions or a link to a complete working demo (I've seen a lot of suggestions and code snippets that just don't seem to work!!) appreciated. I'm certain somebody's done this and got it working surely.
don't pass your model classes around. create a viewmodel with the data you need for the view, or, in your case, the json output. i see where you tried projecting it into an anonymous type, but project it into a concrete viewmodel and it should work perfectly.

Updating a many-to-many relationship

I've asked the question a few different times in a few different ways and I haven't yet gotten any responses. I'm trying again because I feel like my solution is too convoluted and I must be missing something simpler to do.
Using EF 4.1, POCO, DbContext API, AutoMapper, and Razor in an MVC 3 application.
I have a many-to-many relationship between two of my entities: Proposals and CategoryTags. I can successfully map (Automapper) a Proposal to my ProposalViewModel including the collection of CategoryTags.
In my View, I use javascript to allow the user to add, update, and remove tags by dynamically creating elements, each one that stores the ID of the chosen tag.
I can successfully post my ViewModel back to my controller with it's CategoryTags collection populated (although only with the ID property for each CategoryTag).
When that ViewModel is posted back to my controller, I don't know how to get those tags from the ViewModel and add them to my Model in such a way that db.SaveChanges() updates the database properly.
The only way I've had any success is to disconnect the CategoryTags collection in mapping (by namig them differently), iterate through each tag and manually look it up in my context and then call the .add() method. This is sloppy for a number of reasons which leads me to believe I'm doing it wrong.
Can anyone offer any direction at all?
UPDATE:
For anyone who is interested, my functional code:
Dim p As New Proposal
Dim tempTag As CategoryTag
p = AutoMapper.Mapper.Map(Of ProposalViewModel, Proposal)(pvm)
db.Proposals.Attach(p)
db.Entry(p).Collection("CategoryTags").Load()
For Each ct In pvm.Tags
tempTag = db.CategoryTags.Find(ct.Id)
If tempTag Is Nothing Then
Continue For
End If
If ct.Tag = "removeMe" Then
p.CategoryTags.Remove(tempTag)
Continue For
End If
p.CategoryTags.Add(tempTag)
Next
db.Entry(p).State = EntityState.Modified
db.SaveChanges()
Return RedirectToAction("Index")
The only working way is doing this manually - you can read full description of the problem if you want. The description is related to ObjectContext API but DbContext API is just wrapper suffering same issues (actually DbContext API suffers even more issues in this scenario and because of that I will skip solution with manually setting relationships).
In short. Once you post your data back to the controller you must create new context instance and attach your Proposal and realated CategoryTags. But after that you must inform the context about changes you did. It means you must say context which tags have been added to proposal and which have been removed. Otherwise context cannot process your changes because it doesn't do any automatic merge with data in database.
The easiest way to solve this is loading current Proposal with related CategoryTags from database (= you will have attached instances) and merge incoming data into attached object graph. It means you will manually remove and add tags based on posted values.

Entity Framework 3.5 - How to load children

My questions is probably very simple, how do you load children/subclasses. There is no "load" or anything like it that I can find to have the context load the children.
the context class is of ObjectContext type, see below:
public partial class RTIPricingEntities : global::System.Data.Objects.ObjectContext
Product
Product.ModifiedByUser (how to load this class, when loading product??)
Product.Category (how to load the categories when loading product?)
You can eager load:
var q = from p in Context.Products
.Include("ModifiedByUser")
.Include("Category")
select p;
...or project:
var q = from p in Context.Products
select new
{
Id = p.Id,
Name = p.Name
ModifiedByUserName = p.ModifiedByUser.Name,
CategoryName = p.Category.Name
}
The advantage of projection is you get only the data you need, not the whole of every referenced entity. Advantage of eager loading is that returned entities do change tracking. Pick the right technique for the problem at hand.
Update
Yes, it is important to mention that you are using RIA Services. I presume you're also working within the client. This makes things completely different.
In RIA Services, it is very important to make sure that you return the entire graph of entities you require in the initial load. You don't want to call anything like .Load() on an entity, because that would be another hot to the server, which is bad for performance. If you are in, for example, a Silverlight client and request a list of instances from the server and their related properties are not already materialized, it is already too late. Also, Include will not work within a Silverlight client. Therefore, RIA Services has server-side tools you can use to ensure that you return the correct, fully materialized object graph initially.
What you need to do instead is used IncludeAttribute inside your RIA Services server. You can create a "buddy" metadata class to decorate your entity model with [Include]. There are examples in the RIA Services overview document, section 4.8.
Using the .Include() as many others have suggested is a great way to achieve what you need.
However, sometimes you might need to "re-load" something later on that you didn't "include", or that you only need sometimes, so putting an Include statement might be a waste of computing cycles in many cases.
In case of a singular relationship like "Product.Category" (where Product.Category is your navigation property from product to category), you most likely also have a "Product.CategoryReference" element. You can check that to see if it's loaded or not, and if not, you can load it "on demand":
if(!Product.CategoryReference.IsLoaded)
{
Product.CategoryReference.Load();
}
Now your referenced "Category" should be in memory and ready to use.
If you have a navigation property which references a collection of things (e.g. "Parts" for a product), you can do the same thing, directly on the navigation property:
if(!Product.Parts.IsLoaded)
{
Product.Parts.Load();
}
That can be a useful technique for "loading on demand" of single or collection type navigation properties if you haven't "included" them into your EF query.
Marc
You can use the Include() method of the System.Data.Objects.ObjectQuery. This method specifies the related objects to include in the query results and calls to Include() can be chained together to load multiple related objects.
For example to load ModifiedByUser and Category you would use a query like this:
var q = from p in context.Products.Include("ModifiedByUser").Include("Category")
select p;
If your Category entity also had a ModifiedByUser entity that you wanted to load you would use a query like this:
var q = from p in context.Products
.Include("ModifiedByUser")
.Include("Category.ModifiedByUser")
select p;
See Shaping Query Results on MSDN for further examples.
I have noticed that the above mentioned solution by Craig does not load both the ModifiedByUser and Category. It only loads the last object collection which in this case is "Category".
var q = from p in Context.Products
.Include("ModifiedByUser")
.Include("Category")
select p;
However, if you swap the order, to make it .Include("Category").Include("ModifiedByUser"), then ModifiedByUser is loaded. The wierd thing is that the IsLoaded property of both the object collection will show "true", however the Count for the first object collection will always be zero. Not sure why this is the case.

Resources