EF Code First Study notes: Relationships

Source: Internet
Author: User

This article reproduced: http://www.cnblogs.com/Gyoung/archive/2013/01/22/2869782.html

One -to-many relationships

A one-to-many relationship is most commonly used in projects. Code first also has a good support for a one-to-many relationship. In many cases we do not need to be deliberately configured, Code first can detect the relationship between the model through some reference properties, navigation properties, etc., and automatically generate foreign keys for us. Observe the following classes:

View Code
public class Destination    {public        int DestinationId {get; set;}        public string Name {get; set;}        public string Country {get; set;}        public string Description {get; set;}        Public byte[] Photo {get; set;}        Public list<lodging> lodgings {get; set;}    }    public class Lodging    {public        int Lodgingid {get; set;}        public string Name {get; set;}        public string Owner {get; set;}        public bool Isresort {get; set;}        Public decimal Milesfromnearestairport {get; set;}        Public Destination Destination {get; set;}    }

Code first observes that there is a reference property to destination in the lodging class, and that destination has a set navigation property lodgings, so it is inferred that the destination-lodging relationship is a one-to-many relationship. Therefore, in the generated database, a foreign key is automatically generated for the lodging table:

In fact, as long as there is a reference attribute in a class, that is:

View Code
public class Destination    {public        int DestinationId {get; set;}        public string Name {get; set;}        public string Country {get; set;}        public string Description {get; set;}        Public byte[] Photo {get; set;}    }    public class Lodging    {public        int Lodgingid {get; set;}        public string Name {get; set;}        public string Owner {get; set;}        public bool Isresort {get; set;}        Public decimal Milesfromnearestairport {get; set;}        Public Destination Destination {get; set;}    

or a navigation property exists in another class:

View Code
public class Destination    {public        int DestinationId {get; set;}        public string Name {get; set;}        public string Country {get; set;}        public string Description {get; set;}        Public byte[] Photo {get; set;}        Public list<lodging> lodgings {get; set;}    }    public class Lodging    {public        int Lodgingid {get; set;}        public string Name {get; set;}        public string Owner {get; set;}        public bool Isresort {get; set;}        Public decimal Milesfromnearestairport {get; set;}    

Code first detects a one-to-many relationship between them and automatically generates foreign keys.

Specify foreign keys

Of course we can also add a foreign key to the class ourselves. By default, if your foreign key name is canonical, code first sets the property to a foreign key, and no longer automatically creates a foreign key, such as:

View Code
public class Destination    {public        int DestinationId {get; set;}        public string Name {get; set;}        public string Country {get; set;}        public string Description {get; set;}        Public byte[] Photo {get; set;}        Public list<lodging> lodgings {get; set;}    }    public class Lodging    {public        int Lodgingid {get; set;}        public string Name {get; set;}        public string Owner {get; set;}        public bool Isresort {get; set;}        Public decimal Milesfromnearestairport {get; set;}        FOREIGN key public         int Targetdestinationid {get; set;}        Public Destination Target {get; set;}    

Canonical naming means conforming to: named "[Target type key name],[target type name]+[target type key name]" or "[navigation property name]+[target type key name]", where the target type is destination, The corresponding name is: Destinationid,destinationdestinationid,targetdestinationid

What does code first do with a column that is named nonstandard?

For example, we will change the foreign key to:

public int Tardestinationid {get; set;}

Then rebuild the database:

You can see that code first does not recognize that Tardestinationid is a foreign key, so you create a foreign key: Target_destinationid. At this point we're going to tell code first that the property is a foreign key.

Specify a foreign key using data annotations:

        [ForeignKey ("Target")]        public int Tardestinationid {get; set;}        Public Destination Target {get; set;}

Or

        public int Tardestinationid {get; set;}        [ForeignKey ("Tardestinationid")]        Public Destination Target {get; set;}

Note that the ForeignKey position is different, and the parameters of the subsequent bands are different. In this way, the generated database is what we expect. Code first does not generate any more foreign keys.

Specify foreign keys with the fluent API:

Modelbuilder.entity<lodging> (). hasrequired (p = p.target). Withmany (L = l.lodgings). Hasforeignkey (p = p.tardestinationid);

Cases where multiple references to the same entity

Let's consider the following scenario:

View Code
public class Lodging    {public        int Lodgingid {get; set;}        public string Name {get; set;}        public string Owner {get; set;}        public bool Isresort {get; set;}        Public decimal Milesfromnearestairport {get; set;}         Public Destination Target {get; set;}        First Contact public person        primarycontact {get; set;}        Second contact public person        secondarycontact {get; set;}     }     public class person    {public        int PersonID {get; set;}        public string FirstName {get; set;}        public string LastName {get; set;}        Public list<lodging> primarycontactfor {get; set;}        Public list<lodging> secondarycontactfor {get; set;}     }

Lodging (INN) has two references to the person table, namely Primarycontact and Secondarycontact, and There are also navigation to these two contacts in the person table: Primarycontactfor and Secondarycontactfor.

See what kind of database code first will generate by default

God, four foreign keys were generated. Because there are two sets of type-like navigation properties and reference properties, Code first cannot determine the correspondence between them, and a relationship is created for each property individually. This is certainly not what we expected, and in order for code first to know the correspondence between them, the inverse navigation property is used here to solve the problem.

Using Data Annotations:

       First Contact        [Inverseproperty ("Primarycontactfor")] public person         primarycontact {get; set;}        Second contact person        [Inverseproperty ("Secondarycontactfor")]         

Or use the fluent API:

Modelbuilder.entity<lodging> (). Hasoptional (L = l.primarycontact). Withmany (p = p.primarycontactfor);
Modelbuilder.entity<lodging> (). Hasoptional (l=>l.secondarycontact). Withmany (p=>p.secondarycontactfor);

And then rebuild the database, the results

Many-to-many relationships

If there are two classes, each of which is a navigation property pointing to another class, Code first considers the two classes to be a many-to-many relationship, for example:

View Code
  public class Activity     {public         int ActivityID {get; set;}         [Required, MaxLength ()]          public string Name {get; set;}          Public list<trip> Trips {get; set;}     }    public class trips    {public        int tripid{get;set;}        Public DateTime Startdate{get;set;}        Public DateTime EndDate {get; set;}        Public decimal COSTUSD {get; set;}        Public byte[] RowVersion {get; set;}        Public list<activity> Activities {get; set;}    }

A trip class can have a activites schedule, and an activity schedule can plan several trips, obviously a many-to-many relationship. Let's see how the default generated database is:

As you can see, Code first generates an intermediate table activitytrips, which associates the primary keys of the other two tables as foreign keys to the middle table. The name of the key in the middle table defaults to "[Target type name]_[target type key name]".

Specify Table name

If we want to specify the name and key name of the intermediate table, we can configure it with the fluent API.

Modelbuilder.entity<trip> (). Hasmany (t = t.activities). Withmany (A = a.trips). Map (M + =                {                    m.totable ("tripactivities");                    M.mapleftkey ("Tripidentifier");//corresponds to the primary key of trip                    M.maprightkey ("ActivityID");                });

Or:

Modelbuilder.entity<activity> (). Hasmany (A = a.trips). Withmany (t = t.activities). Map (M + =                {                    m.totable ("tripactivities");                    M.mapleftkey ("ActivityID");//corresponds to the activity's primary key                    M.maprightkey ("Tripidentifier");                });
a pair of relations

If we are going to configure two classes to be one-on-one, the corresponding reference properties are configured in two classes, such as:

View Code
public class person    {public        int PersonId {get; set;}        public int SocialSecurityNumber {get; set;}        public string FirstName {get; set;}        public string LastName {get; set;}        1540977490 public        byte[] RowVersion {get; set;}        Public Personphoto Photo {get; set;}    }    public class Personphoto    {        [Key] public        int PersonId {get; set;}        Public byte[] Photo {get; set;}        public string Caption {get; set;}        Public person Photoof {get; set;}    }

We have a picture (Personphoto) for one (person), but if we generate a database based on such a model for error:

The principal side of the association between the type "Breakaway.personphoto" and "Breakaway.person" cannot be determined. The principal side of this association must be explicitly configured using the relational Fluent API or data annotations

Because code first cannot confirm which is the dependent class,必须使用Fluent API或Data Annotations进行显示配置。

Use Data Annotations :

View Code
public class person    {public        int PersonId {get; set;}        public int SocialSecurityNumber {get; set;}        public string FirstName {get; set;}        public string LastName {get; set;}        1540977490 public        byte[] RowVersion {get; set;}        Public Personphoto Photo {get; set;}    }    public class Personphoto    {        [Key, ForeignKey (' Photoof ')] public        int PersonId {get; set;}        Public byte[] Photo {get; set;}        public string Caption {get; set;}        Public person Photoof {get; set;}    }

Using the fluent API:

Modelbuilder.entity<personphoto> (). hasrequired (p = p.photoof). Withoptional (p = p.photo);

Note: PersonID in the Personphoto table is both a foreign key and must be a primary key

EF Code First Study notes: Relationships

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.