6

I have these classes:

public class Product
{
    [Key]
    public virtual int ProductId { get; set; }
    public virtual string ProductName { get; set; }
    public virtual string Category { get; set; }

    public virtual IList<ProductPricing> ProductPriceList { get; set; }


    [Timestamp]
    public virtual byte[] Version { get; set; }
}

public class ProductPricing
{        

    // no ProductId here
    public virtual Product Product { get; set; }

    [Key]
    public virtual int ProductPricingId { get; set; }

    public virtual DateTime EffectiveDate { get; set; }
    public virtual decimal Price { get; set; }


}

This is my modelBuilder:

modelBuilder.Entity<Product>().
    HasMany(x => x.ProductPriceList)
   .WithRequired()
   .HasForeignKey(x => x.Product);

This is the error:

The foreign key component 'Product' is not a declared property on type 'ProductPricing'. Verify that it has not been explicitly excluded from the model and that it is a valid primitive property.

UPDATE

I've tried the following, corresponding errors below the code

modelBuilder.Entity<Product>()
    .HasMany(x => x.ProductPriceList)
    .WithRequired();

{"Invalid column name 'Product_ProductId1'.\r\nInvalid column name 'Product_ProductId'.\r\nInvalid column name 'Product_ProductId1'."}

modelBuilder.Entity<Product>()
    .HasMany(x => x.ProductPriceList)
    .WithRequired()
    .Map(x => x.MapKey("ProductId"));

{"Invalid column name 'Product_ProductId'."}

modelBuilder.Entity<Product>()
    .HasMany(x => x.ProductPriceList)
    .WithRequired(x => x.Product);

{"Invalid column name 'Product_ProductId'.\r\nInvalid column name 'Product_ProductId'."}

modelBuilder.Entity<Product>()
    .HasMany(x => x.ProductPriceList)
    .WithRequired(x => x.Product)
    .Map(x => x.MapKey("ProductId"));

{"Multiplicity constraint violated. The role 'Product_ProductPriceList_Source' of the relationship 'TestEfCrud.Mappers.Product_ProductPriceList' has multiplicity 1 or 0..1."}

If it could help, here's the DDL:

create table Product
(
ProductId int not null identity(1,1) primary key,
ProductName varchar(100) not null,
Category varchar(100) not null,
Version rowversion not null
);

create table ProductPricing
(
ProductId int not null references Product(ProductId),
ProductPricingId int identity(1,1) not null primary key,
EffectiveDate datetime not null,
Price decimal(18,6) not null
);

UPDATE 2

I've tried this answer, which looks a bit similar to my case, mapping originated from child entity How to map parent column in EF 4.1 code first

However, using this:

modelBuilder.Entity<ProductPricing>()
    .HasOptional(x => x.Product)
    .WithMany()
    .Map(x => x.MapKey("ForeignKeyColumn"));

and this:

modelBuilder.Entity<ProductPricing>()
    .HasRequired(x => x.Product)
    .WithMany()
    .HasForeignKey(x => x.Product);

Both resulted to this error:

{"Invalid column name 'Product_ProductId1'.\r\nInvalid column name 'Product_ProductId1'.\r\nInvalid column name 'Product_ProductId1'."}

Community
  • 1
  • 1
Hao
  • 8,047
  • 18
  • 63
  • 92

2 Answers2

5

I don't understand why do you use fluent mapping? Your model should be mapped by default conventions. If you want to map it with fluent mapping use:

modelBuilder.Entity<Product>()
            .HasMany(x => x.ProductPriceList) // Product has many ProductPricings
            .WithRequired(y => y.Product)     // ProductPricing has required Product
            .Map(m => m.MapKey("ProductId")); // Map FK in database to ProductId column
Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • I've tried not putting any modelBuilder fluent mapping, expecting convention-over-configuration would kick in(my classes are typical of greenfield ones), but alas, it has error. `{"Invalid column name 'Product_ProductId'.\r\nInvalid column name 'Product_ProductId'.\r\nInvalid column name 'Product_ProductId'."}` – Hao Aug 03 '11 at 08:39
  • Are you using existing database? – Ladislav Mrnka Aug 03 '11 at 08:47
  • Existing database with one row only on parent (Product) – Hao Aug 03 '11 at 08:49
  • I add info to the question, I posted the DDL – Hao Aug 03 '11 at 08:53
  • Ok, I modified the answer so it should map the FK to correct column. – Ladislav Mrnka Aug 03 '11 at 09:07
  • I already tried your modified answer, I just mis-pasted the code in my updated post. It doesn't work too – Hao Aug 03 '11 at 09:26
  • Massive brainfart on me there, your last modified code(which I've tried even before you gave an answer) works now. I cannot reproduce what causes the error, should have used version control. Thanks for suggesting they are the same mapping(albeit from the reverse side of the relation), I prefer starting from the principal, will accept your answer :-) Care to suggest any free SVN server software with graphical admin? It's frustrating not being able to reproduce the error. – Hao Aug 04 '11 at 01:45
  • I'm using TortoiseSVN as a client and it offers me everything I need. – Ladislav Mrnka Aug 04 '11 at 08:06
  • @LadislavMrnka I'm not a big fan of using the default mapping conventions. Firstly, it makes code more difficult to debug, especially for persons who are not yet well versed in the specific technology. Secondly, what happens if the conventions change between different versions of EF and you update to the newest version, unaware of the change? Thirdly, it makes articles/forum posts less reliable, as the assumptions/conventions they were based on might have changed. In my opinion it is better to disable conventions and explicitly manage your code - much more visibility and much less guessing –  Jun 03 '14 at 19:42
2

This has the correct answer:

http://agilenet.wordpress.com/2011/04/18/entity-framework-code-first-specify-foreign-key-name-in-one-to-many-relationship-with-fluent-api/

I almost got it:

modelBuilder.Entity<ProductPricing>()
    .HasRequired(x => x.Product)
    .WithMany()
    .Map(x => x.MapKey("ProductId"));

I just forgot to put the principal's dependent(i.e. ProductPriceList. I hope I'm getting the right terminology, wanted to stay away from parent child terminology ^_^):

modelBuilder.Entity<ProductPricing>()
    .HasRequired(x => x.Product)
    .WithMany(x => x.ProductPriceList)
    .Map(x => x.MapKey("ProductId"));

Entity Framework's Fluent Mapping is hardly fluent, there's some stutter you could unwittingly commit if you are not very familiar with each method's nuances :-) Lookie that, I almost got it correct. Passing both ProductPricing and ProductPriceList look redundant, hardly intuitive.

EF's fluent mapping is hardly a good fluent(of which intuitiveness should be an innate quality) interface citizen, isn't it?

Hao
  • 8,047
  • 18
  • 63
  • 92
  • I just tested my mapping and it does exactly what you want. What you described is just the same mapping from reverse side of the relation. – Ladislav Mrnka Aug 03 '11 at 22:51