Reputation: 6968
I'm trying to use code-first
to model my db.
What I'm trying to map here is a 0 -> *
relationship for Users
and Challenges
.
E.g A user can have 0 or more challenges associated with them. A challenge can have 0 or more users associated with them.
This is the code I'm using, the problem is that the challenges table is generated with a UserAccount_ID
property.
public class UserAccount
{
public int Id { get; set; }
public string Username { get; set; }
public virtual List<Challenge> Challenges { get; set; }
}
public class Challenge
{
public int Id { get; set; }
public string ChallengeId {get; set;}
public string Name { get; set; }
public string Description { get; set; }
public virtual List<Competitor> Competitors { get; set; }
}
public class Competitor
{
public int Id { get; set; }
public string Username { get; set; }
public int Rank { get; set; }
}
And the incorrect property:
I've tried adding this to my context class but it doesn't have any effect:
protected override void OnModelCreating(DbModelBuilder mb)
{
mb.Entity<UserAccount>()
.HasMany(o1 => o1.Challenges)
.WithOptional();
base.OnModelCreating(mb);
}
Edit
Updated title and question - relationship is not zero to many but many to many.
Upvotes: 1
Views: 451
Reputation: 1917
There are multiple Conventions for achieving Many to Many
and One to Many
relationship in entity framework
. Will try to mention all .Hope these will be helpful.
UPDATE (as OP wants Many to Many): MANY to MANY Relationship
Convention 1 :
Collection navigation properties in both models
public class UserAccount
{
public int Id { get; set; }
public string Username { get; set; }
public ICollection<Challenge> Challenges { get; set; }
}
public class Challenge
{
public int Id { get; set; }
public string ChallengeId {get; set;}
public string Name { get; set; }
public string Description { get; set; }
public ICollection<UserAccount> UserAccounts { get; set; }
}
Other ways for acheiving the same
mb.Entity<UserAccount>()
.HasMany(r => r.Challenges)
.WithMany()
.Map(m =>
{
m.MapLeftKey("UserAccountId");
m.MapRightKey("ChallengeId");
m.ToTable("UserAccountChallenge"); //Junction Table
});
ONE to MANY Relationship
Convention 1:
This can be achieved by including reference navigation property of type
UserAccount
in theChallenge
public class Challenge
{
public int Id { get; set; }
public string ChallengeId {get; set;}
public string Name { get; set; }
public string Description { get; set; }
public UserAccount UserAccount{get;set;}
}
Convention 2:
Another convention is to include collection navigation property in
UserAccount
public class UserAccount
{
public int Id { get; set; }
public string Username { get; set; }
public ICollection<Challenge> Challenges { get; set; }
}
Convention 3:
Including navigation property at both ends will also result in one-to-many relationship
public class Challenge
{
public int Id { get; set; }
public string ChallengeId {get; set;}
public string Name { get; set; }
public string Description { get; set; }
public UserAccount UserAccount{get;set;}
}
public class UserAccount
{
public int Id { get; set; }
public string Username { get; set; }
public ICollection<Challenge> Challenges { get; set; }
}
Convention 4:
Fully defined relationship at both ends will creates one-to-many relationship
public class Challenge
{
public int Id { get; set; }
public string ChallengeId {get; set;}
public string Name { get; set; }
public string Description { get; set; }
public int UserAccountId { get; set; }
public UserAccount UserAccount{get;set;}
}
Configure One-to-Many Relationship using Fluent API
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// configures one-to-many relationship
modelBuilder.Entity<UserAccount>()
.HasRequired<Challeng>(s => s.ChallengId)
.WithMany(g => g.UserAccount)
.HasForeignKey<int>(s => s.ChallengId);
}
Upvotes: 1
Reputation: 39326
That column comes from your relationship between Challenge
and UserAccount
. You could declare the FK property in your model:
public class Challenge
{
public int Id { get; set; }
public string ChallengeId {get; set;}
public string Name { get; set; }
public string Description { get; set; }
//Add these properties
public int UserAccountId{get;set;}
public UserAccount UserAccount{get;set;}
public virtual List<Competitor> Competitors { get; set; }
}
By default EF use some name conventions to identify the FK properties in your model, so it should be fine with that name. Now, if you are using Fluent Api, then I suggest to configure the relationship as you are intending to do:
protected override void OnModelCreating(DbModelBuilder mb)
{
mb.Entity<UserAccount>()
.HasMany(o1 => o1.Challenges)
.WithOptional(e=>e.UserAccount);
.HasForeignKey(e=>e.UserAccountId);
base.OnModelCreating(mb);
}
Now if you don't want to include the FK property and the navigation property in your Challenge entity but you want to rename the FK property you can do this:
protected override void OnModelCreating(DbModelBuilder mb)
{
mb.Entity<UserAccount>()
.HasMany(o1 => o1.Challenges)
.WithOptional();
.Map(m => m.MapKey("UserAccountId"));
base.OnModelCreating(mb);
}
Thinking a little more about your model it is true that maybe what you are really pursuing is a many to many relationship, if that if the case you can configure this way:
mb.Entity<UserAccount>()
.HasMany(r => r.Challenges)
.WithMany() // No navigation property here
.Map(m =>
{
m.MapLeftKey("UserAccountId");
m.MapRightKey("ChallengeId");
m.ToTable("UserAccountChallenge");
});
Upvotes: 2