views:

2308

answers:

3

I'm new to EF 4.0, so maybe this is an easy question. I've got VS2010 RC and the latest EF CTP. I'm trying to implement the "Foreign Keys" code-first example on the EF Team's Design Blog, http://blogs.msdn.com/efdesign/archive/2009/10/12/code-only-further-enhancements.aspx.

public class Customer
{
   public int Id { get; set; 
   public string CustomerDescription { get; set; 
   public IList<PurchaseOrder> PurchaseOrders { get; set; }
}

public class PurchaseOrder
{
   public int Id { get; set; }
   public int CustomerId { get; set; }
   public Customer Customer { get; set; }
   public DateTime DateReceived { get; set; }
}

public class MyContext : ObjectContext
{
   public RepositoryContext(EntityConnection connection) : base(connection){}
   public IObjectSet<Customer> Customers { get {return base.CreateObjectSet<Customer>();} }
}

I use a ContextBuilder to configure MyContext:

{
   var builder = new ContextBuilder<MyContext>();

   var customerConfig = _builder.Entity<Customer>();
   customerConfig.Property(c => c.Id).IsIdentity();

   var poConfig = _builder.Entity<PurchaseOrder>();
   poConfig.Property(po => po.Id).IsIdentity();

   poConfig.Relationship(po => po.Customer)
      .FromProperty(c => c.PurchaseOrders)
      .HasConstraint((po, c) => po.CustomerId == c.Id);

   ...
}

This works correctly when I'm adding new Customers, but not when I try to retrieve existing Customers. This code successfully saves a new Customer and all its child PurchaseOrders:

using (var context = builder.Create(connection))
{
   context.Customers.AddObject(customer);
   context.SaveChanges();
}

But this code only retrieves Customer objects; their PurchaseOrders lists are always empty.

   using (var context = _builder.Create(_conn))
   {
      var customers = context.Customers.ToList();
   }

What else do I need to do to the ContextBuilder to make MyContext always retrieve all the PurchaseOrders with each Customer?

+2  A: 

Well the solution turned out to be simple, as I suspected it might. I called the context.LoadProperty() method for each individual customer:

using (var context = _builder.Create(_conn))
{
    var customers = context.Customers.ToList();
    foreach (var customer in customers)
    {
        context.LoadProperty<Customer>(customer, c => c.PurchaseOrders);
    }
    return customers;
}
SirEel
i'd be cautious about this approach as you are making n round trips to the database, one for each customer. And what if you had several child collections on Customer? A better approach would be the use of Include (see below) which will retrieve it all in a single query to the DB.
Isaac Abraham
+1  A: 

I'm working with the released version of 4.0/VS 2010/EF and I can't seem to find the namespace where the ContextBuilder is stored. In the CTP examples I've seen it is in 'Microsoft.Data.Objects', but I can't seem to find that reference. I had no issues creating a Model-First example, but I'm stuck on the Code-First example I'm working with...any help is greatly appreciated!

Danny Douglass
You need to download it seperately: http://stackoverflow.com/questions/2739808/entity-framework-contextbuilder-namespace
Chris
+1  A: 

You could also use:

var customers = context.Customers.Include("PurchaseOrders").ToList();

Or enable LazyLoading in the ContextOptions :

context.ContextOptions.LazyLoadingEnabled = true;

Just be careful with deferred loading if you are serializing the objects or you may end up querying the entire database.

Daniel Skinner