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.