Sam
Sam

Reputation: 15771

Entity Framework 1:0 or 1 Relationship

I have the following model:

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

public class Customer
{
    public int Id { get; set; }
    public int UserId { get; set; }
    public User User { get; set; }
    ...
}

What I want to have is the Customer has to have an User, but can only have one, and the User does not have to have a Customer.

I would like to do it with the Fluent API, but I can't manage to get it to work so that both Customer and User have their Id properties be Identity Fields.

Upvotes: 1

Views: 629

Answers (1)

ocuenca
ocuenca

Reputation: 39326

When you are configuring an one-to-one relationship, Entity Framework requires that the primary key of the dependent also be the foreign key, in your case it would be:

public class User
{
    public int Id { get; set; }
    public virtual Customer Customer { get; set; }
    ...
}

public class Customer
{
    [Key, ForeignKey("User")]
    public int UserId { get; set; }
    public virtual User User { get; set; }
    ...
}

But you want each entities with its own PK, so, EF lets you do that but you should delete the UserId property from Customer entity, because, as I said before, in this kind of relationship the FK must be PK too. To configure properly your relationship use the Required data annotation as @Claies recommend you in his comment:

public class User
{
    public int Id { get; set; }
    public virtual Customer Customer { get; set; }
    ...
}

public class Customer
{
    [Key]
    public int Id { get; set; }
    [Required]
    public virtual User User { get; set; }
    ...
}

Or you can use Fluent Api, the configuration would be:

modelbuilder.Entity<Customer>().HasRequired(c=>c.User).WithOptional(u=>u.Customer);

Another thing, I recommend you define the navigation properties as virtual. This way, when you consult those properties the first time, they will be lazy loaded. Check this post for more info.

Update 1:

When the key property is an integer, Code First defaults to DatabaseGeneratedOption.Identity. If you want, you can configure explicitly what you need using the [Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)] attributes on the Customer Id.

public class Customer
{
    [Key,DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
}

Or you can use Fluent Api:

modelbuilder.Entity<Customer>().HasKey(t => t.Id)
                               .Property(t => t.Id)
                               .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

Update 2:

I don't understand why is throwing you that exception. I just tested with both variants (Data Annotations and Fluent Api) and everything works well. This is the code generated by Migrations:

 public partial class changeCustomerIdToIdentity : DbMigration
    {
        public override void Up()
        {
            DropIndex("dbo.Customers", new[] { "Id" });
            DropPrimaryKey("dbo.Customers");
            AlterColumn("dbo.Customers", "Id", c => c.Int(nullable: false, identity: true));
            AddPrimaryKey("dbo.Customers", "Id");
            CreateIndex("dbo.Customers", "Id");
        }

        public override void Down()
        {
            DropIndex("dbo.Customers", new[] { "Id" });
            DropPrimaryKey("dbo.Customers");
            AlterColumn("dbo.Customers", "Id", c => c.Int(nullable: false));
            AddPrimaryKey("dbo.Customers", "Id");
            CreateIndex("dbo.Customers", "Id");
        }
    }

I'm afraid your error is happened due to your DB schema. The Id on your Customers table must be FK too. The error means that you have some relation between your entities where foreign key property in dependent entity is defined as store generated, and that is because you are trying change the Id of your Customer entity as Identity, which is FK in your DB.

Upvotes: 1

Related Questions