How to define relationships programmatically in Entity Framework 4.1's Code-First Fluent API
I'm playing around with the new EF4.1 unicorn love.
I'm trying to understand the different ways I can use code-first to programatically define my relationships between a few simple POCO's.
How can I define the following =>
- 1
Team
has 0-manyUser
s. (and aUser
is in 1开发者_StackOverflowTeam
) - 1
User
has 0-or-1Foo
's (but aFoo
has no property going back to aUser
) - 1
User
has 1UserStuff
Here you have examples you are looking for:
public class User
{
public int Id { get; set; }
...
public Foo Foo { get; set; }
public Team Team { get; set; }
public UserStuff UserStuff { get; set; }
}
public class Team
{
public int Id { get; set; }
...
public ICollection<User> Users { get; set; }
}
public class Foo
{
public int Id { get; set; }
...
}
public class UserStuff
{
public int Id { get; set; }
...
}
public class Context : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Foo> Foos { get; set; }
public DbSet<Team> Teams { get; set; }
public DbSet<UserStuff> UserStuff { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.HasRequired(u => u.Team)
.WithMany(t => t.Users);
modelBuilder.Entity<User>()
.HasOptional(u => u.Foo)
.WithRequired();
modelBuilder.Entity<User>()
.HasRequired(u => u.UserStuff)
.WithRequiredPrincipal();
}
}
Lets introduce a few specific classes to illustrate the solutions:
public class Account
{
public long ID { get; set; }
public virtual User User { get; set; }
}
public class User
{
public long ID { get; set; }
public virtual Account Account { get; set; }
public virtual Team Team { get; set; }
}
public class Team
{
public long ID { get; set; }
public long CompanyID { get; set; }
public virtual Company Company { get; set; }
public virtual ICollection<User> Users { get; set; }
}
public class Company
{
public long ID { get; set; }
}
I'm using a helper class to make the mapping classes a bit less verbose:
internal abstract class AbstractMappingProvider<T> : IMappingProvider where T : class
{
public EntityTypeConfiguration<T> Map { get; private set; }
public virtual void DefineModel( DbModelBuilder modelBuilder )
{
Map = modelBuilder.Entity<T>();
Map.ToTable( typeof(T).Name );
}
}
Now for the mappings. Lets do the "1:1" mapping first. In my example user and account are 1:1 related and share the same primary key (only one of them will be an identity column, which in this case is the Account.ID).
internal class UserMapping : AbstractMappingProvider<User>
{
public override void DefineModel( DbModelBuilder modelBuilder )
{
base.DefineModel( modelBuilder );
Map.HasRequired( e => e.Account ).WithRequiredDependent( r => r.User ).WillCascadeOnDelete( true );
}
}
internal class AccountMapping : AbstractMappingProvider<Account>
{
public override void DefineModel( DbModelBuilder modelBuilder )
{
base.DefineModel( modelBuilder );
Map.HasRequired( e => e.User ).WithRequiredPrincipal( r => r.Account ).WillCascadeOnDelete( true );
}
}
In the following mappings we specify that a team has (0..n) users, while a single user is in exactly one team (required). We also specify that a team can have a company, but company does not expose a list of teams.
internal class TeamMapping : AbstractMappingProvider<Team>
{
public override void DefineModel( DbModelBuilder modelBuilder )
{
base.DefineModel( modelBuilder );
Map.HasOptional( e => e.Company ).WithMany().HasForeignKey( e => e.CompanyID );
Map.HasMany( e => e.Users ).WithRequired( r => r.Team );
}
}
internal class CompanyMapping : AbstractMappingProvider<Company>
{
public override void DefineModel( DbModelBuilder modelBuilder )
{
base.DefineModel( modelBuilder );
}
}
Hope this helps!
精彩评论