EF 4.1 code-first: Как спроектировать и отобразить эти объекты? - PullRequest
1 голос
/ 06 октября 2011

У меня есть 3 объекта: Member, AuthenticationToken и Email.

  1. Каждый Member может иметь много AuthenticationTokens
  2. Каждый AuthenticationToken может иметь один или ноль Email
  3. Каждый Member может иметь ноль или один PrimaryEmail (из таблицы Emails)). На самом деле PrimaryEmail является одним из AuthenticationToken s, связанных Email

Так что у меня есть:

public class Member {
    public int MemberId { get; set; }
    public int? PrimaryEmailId { get; set; }
    public virtual Email PrimaryEmail { get; set; }
    public virtual ICollection<AuthenticationToken> AuthenticationTokens { get; set; }
}

public class AuthenticationToken {
    public int AuthenticationTokenId { get; set; }
    public int MemberId { get; set; }
    public virtual Member Member { get; set; }
    public virtual Email Email { get; set; }
}

public class Email {
    public int EmailId { get; set; } // is same as AuthenticationTokenId that the email associated with it
}

С дизайном, который я объяснил вышеЯ могу добавить Member и AuthenticationToken, но когда я хочу прикрепить Email к члену или AuthenticationToken (или обоим), я выдаю эту ошибку:

Оператор INSERT конфликтует с ограничением FOREIGN KEY и т. Д.

Правильно ли это оформление ???Как я могу создать свои таблицы (и объекты) для достижения моей цели?И как я могу отобразить мои объекты в коде в первую очередь?У вас есть идеи, пожалуйста?

enter image description here

1 Ответ

1 голос
/ 19 декабря 2011

Я лично использую свободный API в EF 4.1 для настройки всех своих сущностей, когда я не чувствую, что соглашения по умолчанию меня поймут, поэтому я отвечу, используя свободный API.

Вот как я бы настроил модели:

public class Member
{
    public Member()
    {
        AuthenticationTokens = new List<AuthenticationToken>();
    }

    public int MemberId { get; set; }

    public virtual Email PrimaryEmail { get; set; }
    public virtual ICollection<AuthenticationToken> AuthenticationTokens { get; set; }
}

public class AuthenticationToken
{
    public int AuthenticationTokenId { get; set; }

    public virtual Email Email { get; set; }
}

public class Email
{
    public int EmailId { get; set; }
}

И это мой контекст и свободная конфигурация:

public class ExampleApplicationContext : DbContext
{
    public ExampleApplicationContext()
        : base("ExampleApplicationConnection")
    {

    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // No cascade on delete because the primary email may be held by an authentication token.
        modelBuilder.Entity<Member>()
            .HasOptional(x => x.PrimaryEmail)
            .WithOptionalDependent()
            .Map(x =>
            {
                x.MapKey("EmailId");
            })
            .WillCascadeOnDelete(false);

        // Cascade on delete because an authentication token not associated with a Member makes no sense.
        modelBuilder.Entity<Member>()
            .HasMany(x => x.AuthenticationTokens)
            .WithRequired()
            .Map(x =>
            {
                x.MapKey("MemberId");
            })
            .WillCascadeOnDelete();

        // No cascade on delete because an email may be held by a Member.
        modelBuilder.Entity<AuthenticationToken>()
            .HasOptional(x => x.Email)
            .WithOptionalDependent()
            .Map(x =>
            {
                x.MapKey("EmailId");
            })
            .WillCascadeOnDelete(false);
    }

    public DbSet<Member> Members { get; set; }
}

Я сделаю все возможное, чтобы объяснить, почему я разработал это так. Прежде всего, кажется, что в вашей модели Member должен быть корневым агрегатом (босс других сущностей). Я имею в виду, что Authentication Token не имеет смысла, если он не принадлежит конкретному Member. Email также не имеет смысла в одиночку, если только он не принадлежит Member или не принадлежит AuthenticationToken. По этой причине AuthenticationToken не имеет свойства, чтобы выяснить, к чему Member он прикреплен (чтобы это выяснить, сначала нужно Member, а затем просто посмотреть на его коллекцию). По сути, все вращается вокруг объекта Member. Без Member невозможно создать AuthenticationToken. А без Member или AuthenticationToken невозможно создать Email.

Я не совсем уверен, насколько вас устраивает свободный API в EF 4.1, поэтому, если у вас есть какие-либо вопросы, оставьте комментарий, и я сделаю все возможное, чтобы ответить на них. Я также включил небольшой пример приложения, которое использовал для построения и проверки модели, представленной выше. Если вы хотите запустить программу (это небольшое консольное приложение), вам просто нужно изменить строку подключения в App.config, чтобы она указала на ваш экземпляр SQL Server.

Одна вещь, которая касается меня, это то, что Email может принадлежать как Member, так и AuthenticationToken. Мое беспокойство связано с тем, что мне пришлось установить несколько интересных каскадных удалений. Однако я не знаю всех ваших требований, и эта настройка, кажется, работает нормально, поэтому это может не быть проблемой.

Пример консольного приложения

...