Alex Rivera | Logout

How to define relationships programmatically in Entity Framework 4.1's Code-First Fluent API

Asked 2011-03-20T10:58:14.727
15

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. 1 Team has 0-many Users. (and a User is in 1 Team)
  2. 1 User has 0-or-1 Foo's (but a Foo has no property going back to a User)
  3. 1 User has 1 UserStuff
Edit
Report

2 Answers

11

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();
    }
}
answered 2011-03-20T15:08:41.070
5

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) user

answered 2011-03-20T14:55:29.547

Your Answer