Entity Framework Model First 1:0..1 Relationship

2019-09-06 00:11发布

问题:

I created the following model in the Entity Framework 5 Model Designer in Visual Studio 2012:

Then I generated the database from the model, which resulted in the following tables in my database:

Please help me understand why Entity Framework is generating a one-to-many relationship for a one-to-zero-or-one association.


Update #1

Furthermore, if I change the association from 1:0..1 to 1:1 like this:

Then not only is there still no one-to-one relationship in the database, but now the one-to-many relationship is flipped around, which seems even more weird to me:


Update #2

In response to Mystere Man's comment and answer, the structure I'm expecting to see in SQL Server, which is a valid 1:0..1 relationship is as follows:

Furthermore, I am able to get this working exactly as intended with the following Code First fluent mapping:

public class UserMap : EntityTypeConfiguration<User>
{
    public UserMap()
    {
        ToTable("Users");

        HasKey(t => t.UserId);

        Property(t => t.UserId)
            .HasColumnName("UserId");

        Property(t => t.Name)
            .HasColumnName("Name")
            .IsRequired()
            .HasMaxLength(50);

        Property(t => t.EmailAddress)
            .HasColumnName("EmailAddress")
            .IsRequired()
            .HasMaxLength(254);

        Property(t => t.CreatedDateTime)
            .HasColumnName("CreatedDateTime");

        HasOptional(t => t.Subscription)
            .WithRequired(t => t.User);
    }
}

public class SubscriptionMap : EntityTypeConfiguration<Subscription>
{
    public SubscriptionMap()
    {
        ToTable("Subscriptions");

        HasKey(t => t.SubscriptionId);

        Property(t => t.SubscriptionId)
            .HasColumnName("SubscriptionId");

        Property(t => t.TypeValue)
            .HasColumnName("TypeValue");

        Property(t => t.CreatedDateTime)
            .HasColumnName("CreatedDateTime");

        Property(t => t.ExpiresDateTime)
            .HasColumnName("ExpiresDateTime");

        HasRequired(t => t.User)
            .WithOptional(t => t.Subscription);
    }
}

So, I know it's possible to achieve this behavior with Code First Entity Framework. My question is why it's not possible to do it with the Model First approach.

What's going on here and why?

Thanks!

回答1:

SQL does not have a way to define a true 1:1 or 1:0..1 data model, except when both entities have the same primary key. Even so, you can't have a 1:1 because you can't insert records into more than one table in a single statement, so the data model has to allow 1:0..1 by virtue of there being a intermediate state where one record will exist without the other.

The only way to do this in SQL is to do exactly what EF is doing here, create a 1:*, and then impose constraints ensure uniqueness (such as a Unique Constraint). However, EF doesn't support constraints (you would have to create them manually) so it's possible to insert more than one record and violate your model.

EDIT:

Since you've clarified that you're talking about Model First, and that you are looking for a shared primary key, then here's what you have to do.

Right click on the Association, and create a referential constraint between Subscription and User. This will then cause EF to generate the 1:0..1 relationship you are looking for.