EF 1 to 1..* relationship

廉价感情. 提交于 2019-12-29 09:59:47

问题


Is there a way to create a one to one-or-more relationship in Entity Framework? I've seen plenty examples showing a 1 to 0..* relationship, but I want to be sure that in the given example Foo can only exist if it has at least one Bar.

class Foo
{
   List<Bar> Bars { get; set; }
}

class Bar
{
    public Foo Foo { get; set; }
}

I see that this is not easily achieved by SQL since I want a kind of NOT NULL at the Foo table instead of at the Bar table, but can Entity Framework handle this?

I realized I asked the wrong question, since I was in fact looking for a 0..1 to 1..* relationship, which is significantly different. This is the question I meant to ask.


回答1:


It's impossible to have a true 1 to 1 relationship in any SQL database that i'm aware of. While Set theory allows for a 1 to 1, in practicality, this is difficult to implement.

It's basically a chicken and egg situation. You can't create Foo because you don't have a Bar, and you can't create Bar because there is no Foo yet. The constraints required to create a 1 to 1 essentially prevent you from inserting any actual rows.

Now, you could disable constraints, insert the data and then re-enable them, but that's a hacky kludge that really defeat the purpose of having constraints in the first place.

So just accept the 1 to 0..* and move on.




回答2:


As close as you can get is something like this:

class Foo
{
    List<Bar> Bars { get; set; }

    [Required]
    public int PrimaryBarId { get; set; }
    public Bar PrimaryBar { get; set; }
}

class Bar
{
    public Foo Foo { get; set; }
}

But note that the database will not enforce

aFoo.PrimaryBar.FooId == aFoo.Id

And this kind of model is tricky to update because of the circular FKs.




回答3:


The difficulties of implementing such a solution and the possibilities are discussed in the example below.


Mapping one-to-one

Mapping one-to-one (when both sides are required) is also a tricky thing.

Let's imagine how this could be represented with foreign keys. Again, a CarId in People that refers to CarId in Car, and a PersonId in Car that refers to the PersonId in People.

Now what happens if you want to insert a car record? In order for this to succeed, there must be a PersonId specified in this car record, because it is required. And for this PersonId to be valid, the corresponding record in People must exist. OK, so let's go ahead and insert the person record. But for this to succeed, a valid CarId must be in the person record — but that car is not inserted yet! It cannot be, because we have to insert the referred person record first. But we cannot insert the referred person record, because it refers back to the car record, so that must be inserted first (foreign key-ception :) ).

So this cannot be represented the 'logical' way either. Again, you have to drop one of the foreign keys. Which one you drop is up to you. The side that is left with a foreign key is called the 'dependent', the side that is left without a foreign key is called the 'principal'. And again, to ensure the uniqueness in the dependent, the PK has to be the FK, so adding an FK column and importing that to your model is not supported.

So here's the configuration:

public class CarEntityTypeConfiguration : EntityTypeConfiguration<Car>
{
  public CarEntityTypeConfiguration()
  {
    this.HasRequired(c => c.Person).WithRequiredDependent(p => p.Car);
    this.HasKey(c => c.PersonId);
  }
}

By now you really should have gotten the logic of it :) Just remember that you can choose the other side as well, just be careful to use the Dependent/Principal versions of WithRequired (and you still have to configure the PK in Car).

public class PersonEntityTypeConfiguration : EntityTypeConfiguration<Person>
{
  public PersonEntityTypeConfiguration()
  {
    this.HasRequired(p => p.Car).WithRequiredPrincipal(c => c.Person);
  }
}

If you check the DB schema, you'll find that it's exactly the same as it was in the case of the one-to-one or zero solution. That's because again, this is not enforced by the schema, but by EF itself. So again, be careful :)



来源:https://stackoverflow.com/questions/44518699/ef-1-to-1-relationship

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!