简体   繁体   中英

Entity Framework - Fluent API Mapping

public class Customer
{
    public int Id { get; set; }

    public int AddressId { get; set; }

    public virtual Address { get; set; }
}

public class Address
{
   public int Id { get; set; }

   public virtual Customer { get; set; }
}

A Customer must have mandatorily an address. An address may or may not have a Customer. The Customer navigation property in Address is like "nullable". I have a unique index in Customer.AddressId table.

Is there any way to do this mapping using fluent API?

Edit:

CREATE TABLE Address
(
    Id           INT NOT NULL IDENTITY PRIMARY KEY,
    AddressLine1 VARCHAR(50),
)

CREATE TABLE Customer
(
     Id         INT NOT NULL IDENTITY PRIMARY KEY,
     Name       VARCHAR(50) NOT NULL,
     AddressId  INT NOT NULL,
     CONSTRAINT FK_Customer_Address FOREIGN KEY(AddressId) REFERENCES Address (Id)
)

i recreated the whole datatabase and model, and was able to add records to both customer and address table.

Basically if a customer can have exactly one address, then that means that an address can have 0 or more customers. (not 0 or 1) IDEALLY. but because of your uniqueness constraints, the Address is always going to end up with 0 or 1 customer record only. But this is a runtime constraint, and EF doesn't know about this at design time. (i think it cannot completely grasp the uniqueness rule for 2 way relationships) EF will model Address-to-Customer as 0:N, and let the runtime deal with the fact that N is never going to be more than 1.

this is because think of the records.

  1. a customerA record, needs to have an AddressA record
  2. an AddressB record could be independently inserted into the Address table.
  3. another CustomerC record in Customer table needs to definitely have an Address record, and this record needs to be AddressB or AddressC. (it cannot be AddressA because of the unique index constraint)
  4. an AddressD record could be independently inserted into the Address table.

so AddressA has 1 customer record, AddressD has 0 customer records.

Now the problem is that, your SQL server knows that a Customer record can have only one Address record, and that Address record needs to be unique.

EF cannot understand the uniqueness part in a bi-directional sense. It knows that a customer needs to have just one address, but cannot enforce that this address needs to be unique. This error will naturally happen, when the underlying INSERT throws an error if you try to insert a customer with an address already belonging to another customer. EF actually does a good job of creating a model, with 1:1 between Customer and Address, because of the uniqueness constraint.

But because it doesn't understand the uniqueness part bi-directionally, it maps multiple Customers to a single Address. (0 or more Customers, instead of 0 or 1)

So your mapping needs to look like this:

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Address>()
            .HasMany(e => e.Customers)
            .WithRequired(e => e.Address)
            .WillCascadeOnDelete(false);
    }

This ensures, that a customer always has a required address entity, and an address has 0 or more customers. (in practice because of the uniqueness constraint, you'll always end up with 0 or 1 customer only in that list) but you cannot enforce it in EF. you need to always fetch the List<Customers> and it is always going to have 0 or 1 element.

If you try to manually modify the mapping and have an optional 0:1 relationship between Address and Customer (instead of 0:N), then EF gets a bit confused and starts throwing IDENTITY insert exceptions for some reason. not sure why.

so you could work with the above mapping, with the assurance that you'll always have 0 or 1 record only, in the List<Customers>

There have been feature requests to completely understand the uniqueness aspect from both sides (translates to a well perceived relational algebra i think). https://data.uservoice.com/forums/72025-entity-framework-feature-suggestions/suggestions/1050579-unique-constraint-ie-candidate-key-support

public class Customer
{
    public int Id { get; set; }
    public Address { get; set; }
}
public class Address
{
   public int Id { get; set; }
   public int? CustomerId { get; set; }
   public virtual Customer { get; set; }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM