我有3个实体:Member
,AuthenticationToken
和Email
。
Member
可能有多个 AuthenticationTokens
AuthenticationToken
可能一个或零 Email
Member
可能有零或一个 PrimaryEmail
(来自Emails
表)。 PrimaryEmail
真的是AuthenticationToken
与之关联的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,但是当我想将一封电子邮件附加到一个成员或AuthenticationToken(或两者)时,我给出了这个错误:
INSERT语句与FOREIGN KEY约束等冲突。
这个设计是否正确? 如何设计我的表(和实体)以实现我的目的? 我如何在代码优先映射我的实体?你有什么想法吗?
答案 0 :(得分:1)
我个人使用EF 4.1中的流畅API来配置我的所有实体,当我觉得默认约定不会理解我时,所以我将使用流畅的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
,则无法创建Email
。
我不完全确定您在EF 4.1中使用流畅的API有多舒服,所以如果您有任何问题请发表评论,我会尽力回答。我还包括一个小样本应用程序,我用它来构建和验证我上面提到的模型。如果要运行程序(它是一个小型控制台应用程序),您只需修改App.config中的连接字符串以指向您的SQL Server实例。
我担心的一件事是Member
可以同时属于AuthenticationToken
和{{1}}。我担心的是,我必须设置一些有趣的级联删除。但是,我不知道您的所有要求,并且此设置似乎工作正常,因此可能不是问题。