Entity Framework one to many relation code first

12,561

You need to map both properties participating in the relationship. You need to add ClientID column to Orders table.

class ClientMapping
{
    ClientMapping()
    {
        this.HasKey(e => e.ClientID).Property(e => e.ID).HasColumnName("ClientID");
        this.Property(e => e.Name).HasColumnName("Name");

        this.HasMany(e => e.Orders).WithRequired(o => o.Client)
           .Map(p => p.MapKey("ClientID")).WillCascadeOnDelete();

        this.ToTable("Clients");
    }
}

class OrderMapping
{
    OrderMapping()
    {
        this.HasKey(e => e.OrderID).Property(e => e.OrderID).HasColumnName("OrderID");
        this.Property(e => e.Details).HasColumnName("Details");
        this.ToTable("Orders");
    }
}

Configuring the relationship from one entity is sufficient.

Share:
12,561
rideronthestorm
Author by

rideronthestorm

Updated on June 04, 2022

Comments

  • rideronthestorm
    rideronthestorm almost 2 years

    I am having my first steps in EF 4.1. Because I was using NHibenate, the code first approach seems to me as the best one. I have problem with good mapping of one-to-many (or many-to-one) realtionship. Let's say I have 2 entities:

    class ClientModel
    {
        int ClientID;
        string Name;
        virtual IList<OrderModel> Orders;
    }
    
    class OrderModel
    {
        int OrderID;
        string Details;
        virtual ClienModel Client;
    }
    

    When I leave it like that, there is an error while generating database - keys in tables are missing. I figured out I can fix it by changing names of the keys to ID (but it's not OK with my naming convention) or by adding [Key] annotation. Even if I add this annotation, still the names of tables are wrong - just like classes names but with 's'. So I tried to use fluent API - I made mappings. But if I set mappings just like here:

    class ClientMapping
    {
        ClientMapping()
        {
            this.HasKey(e => e.ClientID).Property(e => e.ID).HasColumnName("ClientID");
            this.Property(e => e.Name).HasColumnName("Name");
            this.HasMany(e => e.Orders).WithOptional().Map(p => p.MapKey("OrderID")).WillCascadeOnDelete();
            this.ToTable("Clients");
        }
    }
    
    class OrderMapping
    {
        OrderMapping()
        {
            this.HasKey(e => e.OrderID).Property(e => e.OrderID).HasColumnName("OrderID");
            this.Property(e => e.Details).HasColumnName("Details");
            this.HasRequired(e => e.Client).WithMany().Map(p=>p.MapKey("Client")).WillCascadeOnDelete(false);
            this.ToTable("Orders");
        }
    }
    

    the relation betweene tables in database is doubled. What is the proper way to do one-to-many relationship using code-first approach? Am I thinking in a good direction or is it a wrong approach?

    EDIT

    OK, I have done it in the way @Eranga showed, but there is still a problem. When I'm getting Client from database, its Orders property is null (but in database it has some Orders with Order.ClientID == Client.ClientID).

    • Eranga
      Eranga over 12 years
      I tested the configuration given in my answer and it works fine. Make sure Orders is a property not a field.
    • Jo Smo
      Jo Smo over 9 years
      Try virtual List<OrderModel> Orders; instead of virtual IList<OrderModel> Orders;
  • rideronthestorm
    rideronthestorm over 12 years
    "You need to map both properties participating in the relationship. You need to add ClientID column to Orders table." What do you exactly mean by that?
  • Eranga
    Eranga over 12 years
    @rideronthestorm Orders property in ClientModel and Client property in OrderModel as the two participants of the relationship.
  • rideronthestorm
    rideronthestorm over 12 years
    I still don't understand it. Wasn't I mapping both of them? Maybe you could post full code for it? And why do I need ClientID in Orders (OrderModel?)?
  • Eranga
    Eranga over 12 years
    @rideronthestorm I posted the full code for mapping. The way you mapped will be interpreted by EF as two different relationships. Since an Order requires a Client you need to added the foreign key column ClientID to Order table
  • rideronthestorm
    rideronthestorm over 12 years
    Isn't ClienModel Client; enough as a foreign key?
  • rideronthestorm
    rideronthestorm over 12 years
    Amd ypu are saying that I should put int ClientID instead of ClientModel Client? Why there is no Client or ClientID mapping?
  • rideronthestorm
    rideronthestorm over 12 years
    And the other question is what is the difference if I set hasMany in client or withMany in order? These are 2 different ways to describe the same relation?
  • rideronthestorm
    rideronthestorm over 12 years
    I did it like you said - so model has no changes, but mappnigs are like the ones you've posted. The database was generated without errors, but there is something wrong with it, because when I try to generate diagram for it in SQl Management Studio, I get the error "The table '<table_name>' no longer exists in the database" for each of my generated tables. However, they are accessible, I can see their columns, modify them, etc.
  • Eranga
    Eranga over 12 years
    @rideronthestorm You do not ned to add ClientID property to OrderModel. EF will create a column ClientID in Orders table when you map the entities as I have shown. HasMany is used when you map from the many side. WithMany is used when you map form one side of the relationship to the many side.
  • rideronthestorm
    rideronthestorm over 12 years
    "HasMany is used when you map from the many side. WithMany is used when you map form one side of the relationship to the many side." - yes, I know that, but what is the difference in effect? In my example could I use withMany in Client instead of hasMany in order and effect (objects generated) would be the same?