My EF6 relationship isn’t working where the ID > 1, what have I done wrong?

60 Views Asked by At

This is my first dip into Entity Framework - as a long time Linq2Sql guy I never had anyone show me what EF did better. I’ve followed some MS tutorials and I have a context that creates a database and stores stuff easily. I can query it with LINQ so it’s still familiar.

What isn’t working though is a relationship. I have three classes, call them Product, Place, and Price. They all have an int Id. Product and Place both have a virtual icollection, and Price has a property each for Product and Place.

The logical model is that I have a list of products that are sold in zero or more places, and any product might have a different price in each location (think local tax adjustments).

My first test wouldn’t populate the list of prices from the product, so myProduct.Prices was null. I worked around that by getting the list of prices myself var prices = dB.Prices.Where(...)

My problem is when I have more than one Place (Id 1 and 2), and I put in data for multiple prices, the Place is null where the Id is 2.

I have tried adding data directly to the tables (a place with Id 2, anD a price with Place_Id = 2). I have tried adding them with code.

If I go in to the Price table and change both Place_Id to 1, it works in that they both retrieve Place 1. If I set them both to two they both give me null Place. If I set one each way, the one with 1 works and the other is null.

So my relationship works but only when the FK is 1. WTF have I done?

edit: code samples (sorry, I was on my phone earlier)

{ //declared in my dbcontext
...
    public DbSet<Product> Products { get; set; }
    public DbSet<Place> Places{ get; set; }
    public DbSet<Price> Prices{ get; set; }
...
}
//Just to be clear, below are separate from the dbcontext
  public class Product
  {
    public int Id { get; set; }
    public string Name { get; set; }
    ...
    [InverseProperty("Product")]
    public ICollection<Price> Prices { get; set; }
  }

  public class Place
{
    public int Id { get; set; }
    public string Name { get; set; }
    ...
    [InverseProperty("Place")]
    public ICollection<Price> Prices { get; set; }
  }

  public class Price{
    public int Id { get; set; }
    public Product Product { get; set; }
    public Place Place { get; set; }
    ...
  }

I tried inserting rows directly, also I tried

//In the Seed(Context) method of my DbContextInitializer, where db is an instance of my dbcontext

 var a1 = new Place { Name = "Place 1"};
      var a2 = new Place { Name = "Place 2"};
      var p = new Product { Name = "Test Product" };

      db.Products.Add(p);
      db.Associations.Add(a1);
      db.Associations.Add(a2);
      
      db.Prices.Add(new Price { Amount = 10.1m, Place= a1, Product = p });
      db.Prices.Add(new Price { Amount = 3.45m, Place= a2, Product = p });

      db.SaveChanges();

All of that data gets inserted and I can interrogate the database to see it.

The code that is coming unstuck is:

foreach (var p in db.Products.ToList()) //NB if I try this without the ToList I get an exception about an open data reader
      {
        var price = 0m;
        foreach (var o in db.Prices)
        {
//there are two price records which we created above.
//In the first Price, o = {Id = 1, Place_Id = 1, Product_Id = 1}. This works.
//In the second Price, o = {Id = 2, Place_Id = 2, Product_Id = 1}. o.Place is null
//  Yes, there is absolutely a Place {Name = "Place 2", Id = 2} in the database
          if (o.Place.Id == ...)price += o.Amount;
        }
        ...
      }

Something interesting I noticed. If I jam in more products, it works with any product Id. Also (and I suspect this is the underlying issue), I notice that o.Product is of type Product, however o.Place is of type DynamicProxies.Place_Guid - but I'm not understanding why these are different I have declared the properties in identical fashion as you can see above.

0

There are 0 best solutions below