Как программно определить отношения в Code-First Fluent API Entity Framework 4.1

Я играю с новой любовью единорога EF4.1.

Я пытаюсь понять различные способы использования code-first для программного определения взаимосвязей между несколькими простыми POCO.

Как я могу определить следующее =>

  1. 1 Team имеет 0-много Users. (и User находится в 1 Team)
  2. 1 User имеет 0 или 1 Foo (но Foo не имеет свойства, возвращающегося к User)
  3. 1 User имеет 1 UserStuff

person Pure.Krome    schedule 20.03.2011    source источник


Ответы (2)


Здесь у вас есть примеры, которые вы ищете:

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();
    }
}
person Ladislav Mrnka    schedule 20.03.2011
comment
В чем разница между modelBuilder.Entity<User>() .HasOptional(u => u.Foo) .WithRequired(); И modelBuilder.Entity<User>() .HasOptional(u => u.Foo) ? Оба допустят 0-или-1 Foo в User или? - person alwayslearning; 15.05.2012

Давайте представим несколько конкретных классов, чтобы проиллюстрировать решения:

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; }
}

Я использую вспомогательный класс, чтобы сделать классы отображения менее подробными:

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 );
    }
}

Теперь о отображениях. Давайте сначала сделаем отображение "1:1". В моем примере пользователь и учетная запись связаны 1:1 и имеют один и тот же первичный ключ (только один из них будет столбцом идентификации, которым в данном случае является 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 );
    }
}   

В следующих сопоставлениях мы указываем, что в команде есть (0..n) пользователей, в то время как один пользователь находится ровно в одной команде (обязательно). Мы также указываем, что у команды может быть компания, но компания не выставляет список команд.

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 );
    }
}

Надеюсь это поможет!

person Morten Mertner    schedule 20.03.2011
comment
Что вы делаете с EntityTypeConfiguration ? - person Rushino; 20.09.2011
comment
Я не уверен, что ты имеешь в виду? Экземпляр DbModelBuilder, переданный в DefineModel, предоставляет свойство этого типа, которое я предоставляю в AbstractMappingProvider как свойство Map. Это позволяет отдельным производным классам отображения просто использовать Map. для доступа к экземпляру EntityTypeConfiguration, используемому для определения сопоставлений. - person Morten Mertner; 21.09.2011