1

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.

Sam
  • 15,336
  • 25
  • 85
  • 148
  • you don't need fluent api for that, you just need to add the navigation properties, which you aren't showing here. – Claies Jul 12 '15 at 20:05
  • @Claies - So it should look like it does now? With no Fluent Configuration? – Sam Jul 12 '15 at 20:09
  • your title says 1:1 but your description reads as 1:0.1 (1 `User` to 0 or 1 `Customer`) – Claies Jul 12 '15 at 20:11
  • I get the following error if no Fluent Configuration is defined. `Unable to determine the principal end of an association between the types 'ArtImpressions.Core.Domain.Model.User' and 'ArtImpressions.Core.Domain.Model.Customer'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.` – Sam Jul 12 '15 at 20:11
  • @Claies - That is correct. I will update the title. – Sam Jul 12 '15 at 20:12
  • all you need is to have `[Required]` added to the `User` property of the `Customer` class. then, instead of it being a `0.1:0.1` the way it is now (both nullable, neither a principal), `User` will no longer be nullable and will become the principal. – Claies Jul 12 '15 at 20:15
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/83080/discussion-between-sam-and-claies). – Sam Jul 12 '15 at 20:19

1 Answers1

1

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.

Community
  • 1
  • 1
ocuenca
  • 38,548
  • 11
  • 89
  • 102
  • Thank you! Following the above, I still get a migration that does not set the `Customer.Id` to an identity. – Sam Jul 12 '15 at 21:01
  • A dependent property in a ReferentialConstraint is mapped to a store-generated column. Column: 'Id'. When I do what Update 1 says. – Sam Jul 13 '15 at 03:29
  • @Sam, check the Update 2 – ocuenca Jul 13 '15 at 17:36