1

我有 3 个实体:MemberAuthenticationTokenEmail

  1. 每个Member可能有很多 AuthenticationTokens
  2. 每个AuthenticationToken可能有一个或零 Email
  3. 每个都Member可能有零或一 PrimaryEmail(来自Emails表格)。真的PrimaryEmailAuthenticationTokens 的关联 之一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,但是当我想将电子邮件附加到 Member 或 AuthenticationToken(或两者)时,我给出了这个错误:

INSERT 语句与 FOREIGN KEY 约束等冲突。

这个设计对吗???如何设计我的表(和实体)以实现我的目的?以及如何在代码优先中映射我的实体?请问你有什么想法吗?

在此处输入图像描述

4

1 回答 1

1

当我觉得默认约定不能理解我时,我个人使用 EF 4.1 中的 fluent API 来配置我的所有实体,因此我将使用 fluent 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应该是根聚合(其他实体的老板)。我的意思是 aAuthentication Token没有意义,除非它属于特定的Member. AnEmail也没有任何意义,除非它属于 aMember或属于 a AuthenticationToken。出于这个原因AuthenticationToken,没有一个属性可以找出Member它所附加的内容(要找到它,您首先需要一个Member,而不仅仅是查看它的集合)。本质上,一切都围绕着一个Member对象。没有MemberanAuthenticationToken就无法创建。没有 aMember或 anAuthenticationTokenEmail无法创建。

我不完全确定您对 EF 4.1 中的 fluent API 有多满意,所以如果您有任何问题,请发表评论,我会尽力回答。我还包含了一个小型示例应用程序,用于构建和验证我上面介绍的模型。如果您想运行该程序(它是一个小型控制台应用程序),您只需修改 App.config 中的连接字符串以指向您的 SQL Server 实例。

我担心的一件事是它Email可以同时属于 aMember和 an AuthenticationToken。我的担忧来自于我必须设置一些有趣的级联删除。但是,我不知道您的所有要求,而且这个设置似乎工作得很好,所以这可能不是问题。

示例控制台应用程序

于 2011-12-19T01:07:06.950 回答