Reputation: 5048
I'm trying to make one to one relationship. I don't want to use fluent API if it is not necessary. This is what I tried so far:
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
}
public class Person
{
public int Id { get; set; }
[ForeignKey("UserId")]
public UserProfile UserProfile { get; set; }
}
Yes, I know there are few similar questions outhere, but none of them were short and clear. Lot of them also did not work.
Upvotes: 0
Views: 210
Reputation: 19161
It depends a little on what type of table structure you want to achieve. There are various ways of doing this, and there is a good walkthrough for all the options, from Shared Primary Key Assocations to One-to-One Foreign Key Associations in those links. Unfortunately those links make more use of Fluent than Annotations. The samples below use Annotations, as you need.
Shared Primary Key
In theory the Shared Primary Key (horizontal table partitioning, in database terms) is the "correct way". It is also the smallest change you need to do to be able to generate a migration (which will use a Shared Primary Key Association). Note that I would change Person.Id
to Person.UserId
to better show your intent:
// tested in EF 5 and MVC 4.5.
[Table("UserProfile")]
public class UserProfile {
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
}
[Table("Person")] // not required, added for clarity in sample code
public class Person {
// Note the change of property name to reflect that this is a shared primary key,
// using the UserId column in UserProfile as the Primary Key
[Key]
public int UserId { get; set; }
[ForeignKey("UserId")]
public virtual UserProfile UserProfile { get; set; }
}
// The generated migration:
public partial class AddTable_Person : DbMigration
{
public override void Up() {
CreateTable(
"dbo.Person",
c => new {
UserId = c.Int(nullable: false),
})
.PrimaryKey(t => t.UserId)
.ForeignKey("dbo.UserProfile", t => t.UserId)
.Index(t => t.UserId);
}
public override void Down(){
DropIndex("dbo.Person", new[] { "UserId" });
DropForeignKey("dbo.Person", "UserId", "dbo.UserProfile");
DropTable("dbo.Person");
}
}
this then gives you, in effect a 1:0-1
relationship between UserProfile
(which is mandatory) and People
(which is optional, but can have one per person at the most.
If you want to use Id
in Person
then do the following (the migration will change accordingly):
public class Person {
public int Id { get; set; }
[ForeignKey("Id")]
public UserProfile UserProfile { get; set; }
}
Shared Primary Key with two-way navigation
If you want to navigate from UserProfile
to Person
you have more work to do. Simply adding public virtual Person Person { get; set; }
to UserProfile will give you an error:
Unable to determine the principal end of an association between the types 'Test.Models.UserProfile' and 'Test.Models.Person'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
So, we fix it with [Required]
on the Person.UserProfile
property (Person
requires UserProfile
). This gives the same migration as before.
// tested in EF 5 and MVC 4.5.
[Table("UserProfile")]
public class UserProfile {
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
[ForeignKey("UserId")]
public virtual Person Person { get; set; }
}
[Table("Person")] // not required, added for clarity in sample code
public class Person {
[Key]
public int UserId { get; set; }
[ForeignKey("UserId")]
[Required]
public virtual UserProfile UserProfile { get; set; }
}
Again, this works if you use Id
for Person
instead of UserId
:
public class Person {
[Key]
public int Id { get; set; }
[ForeignKey("Id")]
[Required]
public virtual UserProfile UserProfile { get; set; }
}
Upvotes: 4
Reputation: 177133
If you want to create a one-to-one relationship the first thing you must clarify is what is the principal and what the dependent entity in this relationship. Can a Person
exist without UserProfile
or can a UserProfile
exist without Person
?
Because you have started to apply a [ForeignKey]
attribute in Person
I am assuming now that Person
is the dependent, i.e. it cannot exist without UserProfile
.
Correct application of the [ForeignKey]
attribute would then be:
public class Person
{
[ForeignKey("UserProfile")]
public int Id { get; set; }
public UserProfile UserProfile { get; set; }
}
I am not sure if that is sufficient because you don't have a Person
navigation property in UserProfile
. If it doesn't work add this property to UserProfile
:
public Person Person { get; set; }
If you don't want to have such a navigation property you can't avoid Fluent API:
modelBuilder.Entity<Person>()
.HasRequired(p => p.UserProfile)
.WithOptional();
Upvotes: 0
Reputation: 9458
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public virtual Person Person {get;set;}
}
public class Person
{
public int Id { get; set; }
public int UserProfileUserId { get; set; } //Foreign Key
public virtual UserProfile UserProfile { get; set; }
}
Upvotes: 0