EF 4.1 代码优先:如何设计和映射这些实体?

发布于 2024-12-08 08:18:32 字数 1416 浏览 3 评论 0原文

我有 3 个实体:MemberAuthenticationTokenEmail

  1. 每个 Member 可能有许多 AuthenticationTokens
  2. 每个 AuthenticationToken 可能有一个或零个 电子邮件
  3. 每个成员 可能有零个或一个 PrimaryEmail(来自Emails 表)。 实际上,PrimaryEmailAuthenticationToken的关联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 约束等冲突。

这个设计正确吗??? 如何设计我的表(和实体)来实现我的目的? 如何以代码优先方式映射我的实体?请问你有什么想法吗?

在此处输入图像描述

I have 3 entities: Member, AuthenticationToken, and Email.

  1. Each Member may has many AuthenticationTokens
  2. Each AuthenticationToken may has one or zero Email
  3. Each Member may has zero or one PrimaryEmail (from Emails table). Really the PrimaryEmail is one of the AuthenticationTokens's associated Email

So I have:

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
}

With design I explained above, I can add Member and AuthenticationToken, but when I want to attach a Email to a Member or AuthenticationToken (or both) I give this error:

The INSERT statement conflicted with the FOREIGN KEY constraint etc.

Is this design correct???
How can I design my tables (and entities) to achieve my purpose?
And how can I map my entities in code-first? Have you any idea please?

enter image description here

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

横笛休吹塞上声 2024-12-15 08:18:32

当我觉得默认约定无法理解我时,我个人使用 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 似乎应该是根聚合(其他实体的老板)。我的意思是身份验证令牌没有任何意义,除非它属于特定的成员Email 本身也没有任何意义,除非它属于 Member 或属于 AuthenticationToken。因此,AuthenticationToken 没有属性来查明它所附加的 Member(要查明这一点,您首先需要一个 Member 并且而不是仅仅看看它的收藏)。本质上,一切都围绕着 Member 对象。如果没有 Member,则无法创建 AuthenticationToken。如果没有 MemberAuthenticationToken,则无法创建 Email

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

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

示例控制台应用程序

I personally use the fluent API in EF 4.1 to configure all of my entities when I don't feel the default conventions will understand me, so I will answer using the fluent API.

Here is how I would set up the models:

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

And this is my context and fluent configuration:

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

I will do my best here to explain my reasoning as to why I designed it like this. First of all, it appears that in your model Member should be the root aggregate (the boss of the other entities). What I mean is an Authentication Token makes no sense unless it belongs to a specific Member. An Email also makes no sense alone unless it either belongs to a Member or belongs to an AuthenticationToken. For this reason AuthenticationToken does not have a property to find out what Member it is attached to (to find this out you first need a Member and than just look at its collection). Essentially, everything revolves around a Member object. Without a Member an AuthenticationToken cannot be created. And without a Member or an AuthenticationToken an Email cannot be created.

I'm not entirely sure how comfortable you are with the fluent API in EF 4.1, so if you have any questions leave a comment and I will do my best to answer them. I have also included a small sample application that I used to build and verify the model I presented above. If you want to run the program (it is a small Console app) you just have to modify the connection string in App.config to point to your instance of SQL Server.

One thing that concerns me is the fact that Email can belong to both a Member and an AuthenticationToken. My concern comes from the fact that I had to setup some interesting cascade deletes. I don't know all of your requirements, however, and this setup appears to work just fine so that may not be an issue.

Example Console Application

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文