4

I have two models, one for device types, and another for device issues. The relationship here is one(DeviceType) to many(DeviceIssues). Here are the models:

public class DeviceType : ModelBase
{
    public string Manufacture { get; set; }
    public DeviceTypes Type { get; set; }
    public string Model { get; set; }

    public virtual ICollection<DeviceIssue> Issues { get; set; }
}

public class DeviceIssue : ModelBase
{
    public string Description { get; set; }
    public decimal RepairCost { get; set; }

    public int DeviceTypeId { get; set; }
    public virtual DeviceType DeviceType { get; set; }
}

public abstract class ModelBase
{
    public int Id { get; set; }
    public Guid Guid { get; set; }
    public DateTime FirstCreated { get; set; }
    public string LastUpdateUser { get; set; }
    public DateTime LastUpdateDt { get; set; }
    public bool IsDeleted { get; set; }
}

I have to database populated with several entities, using the seed method, and their foreign keys are intact. However when I get the list of device types, I do not also get the associated list of issues for each device. I am using AutoMapper, however, while debugging the variable which stores the query result doesn't show the data either. Here is the code I am using to make the calls:

var result = new List<DeviceTypeDataContract>();
using (var context = new DSPEntities())
{
    var devices = context.DeviceTypes;
    foreach (var device in devices)
    {
        //var issues = context.DeviceIssues.Where(i => i.DeviceTypeId == device.Id).ToList();

        var devi = Mapper.Map<DeviceType, DeviceTypeDataContract>(device);
        result.Add(devi);
    }
}

now as stated, while debugging, inspecting the variable device in foreach(var device in devices), shows the following similar result each time:

device.Issues = null,
device.manufacture = "Apple",
device.Model = "iPhone 3S",
device.Type = DeviceTypes.SmartPhone,

If you notice in my code there is a commented out line of code. This is commented because it throws the following inner exception:

{"There is already an open DataReader associated with this Command which must be closed first."}

I don't know if this has to do with my specific issue or not though.

My question is, how do i retrieve the data from those relationships?

Note: The relationships do exist, because outside the foreach statement, calling the following:

var issues = context.DeviceIssues.Where(i => i.DeviceTypeId == 1).ToList();

gives the following result:

issues[6].Description = "Water Damage",
issues[6].RepairCost = 0.00,
issues[6].DeviceTypeId = 1,
issues[6].DeviceType = [+]{Data.Model.DeviceType},
// The last property holds values similar to above.
// Except now the list of issues is populated.

Note the above comment: "except now the list of issues is populated."

Oxymoron
  • 1,380
  • 2
  • 19
  • 47
  • [`virtual` is inferring lazy-loading](http://stackoverflow.com/questions/5597760/what-effects-can-the-virtual-keyword-have-in-entity-framework-4-1-poco-code-fi). You can adjust lazy-loading in the `DbContext` or use the `.Include()` method when you do to query the primary object (so it grabs associations as well). e.g. `context.DeviceTypes.Include(x => x.DeviceIssues)` – Brad Christie Aug 29 '13 at 12:27

1 Answers1

9

When you decorate associations with virtual you are inferring them to be lazy loaded. This means that the primary collection (in this case DeviceTypes) is loaded but, until you try to access it, Issues won't be populated with any information.

There are multiple ways to get around this, but simplest (and most efficient) is load the associations when you need them using the Include method. e.g.

var devices = context.DeviceTypes.Include(x => x.Issues);

This will load the original collection (DeviceTypes) as well as populate the Issues for each type. This is usually the best way as you're only grabbing information you need to get your unit of work completed when it's needed.

If you find this to be common, however, you can always adjust lazy loading in your DbContext constructor:

public DSPEntities()
{
    this.Configuration.LazyLoadingEnabled = false;
}
Community
  • 1
  • 1
Brad Christie
  • 100,477
  • 16
  • 156
  • 200
  • using this method produces the following error: `Cannot resolve symbol 'Include'` is there an assembly required to use this method? – Oxymoron Aug 29 '13 at 15:10
  • I am using this in a WCF project, and when invoking the specific operation contract that uses this code the following error occurs `An error occurred while receiving the HTTP response to http://xx.xx.x.xx:8200/Services/WCFClient.svc. This could be due to the service endpoint binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down). See server logs for more details.]` – Oxymoron Aug 29 '13 at 15:25
  • 1
    @Oxymoron: enable tracing and see if anything insightful shows up. – Brad Christie Aug 29 '13 at 15:38
  • it has, serialization, circular reference, trying to figure out how to change serialization. found http://stackoverflow.com/questions/6485533/how-to-change-the-serialization-mode-to-unidirectional-in-entity-framework but having trouble understand exactly what i need to do – Oxymoron Aug 29 '13 at 15:47
  • if you're sending the POCOs back, are they marked as `[DataContract]` entities? – Brad Christie Aug 29 '13 at 15:51
  • yes the `[DataContract]` for DeviceTypes `DeviceTypeDataContract` has a `[DataMember]` for DeviceIssues `DeviceIssueDataContract`, also a `[DataContract]`, these are all automapped using automapper. – Oxymoron Aug 29 '13 at 15:58
  • oh.. i get it now... duh x.x – Oxymoron Aug 29 '13 at 16:29