我有一个名为AspNetUsers
的表,它是由AspNetCore.Identity
创建的默认表,我创建了一个名为User
的类,它继承了IdentityUser
并在AspNetUsers
上实现了更多字段:
public class User : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime BirthDate { get; set; }
public string LockoutMessage { get; set; }
public string SessionId { get; set; }
public virtual UserDetails UserDetail { get; set; }
}
然后我创建了另一个名为UserDetails
的类,我不需要此表中的PK
,因为在UserDetails
中我需要存储User
中可用的用户的详细信息,这是AspNetUsers
表:
public class UserDetails
{
//public string Id { get; set; }
public string Biography { get; set; }
public string Country { get; set; }
public string FacebookLink { get; set; }
public string TwitterLink { get; set; }
public string SkypeLink { get; set; }
public string UserId { get; set; }
public virtual User User { get; set; }
}
现在,如果我取消注释Id
属性,迁移工作正常,但我不需要Id
所以我评论了属性并执行此命令:
add-migration Initial-Migration -context DemoAppContext
update-database
在DemoAppContext
课程中,我告诉EF
在FK
上实施UserDetails
:
public class DemoAppContext : IdentityDbContext<User>
{
public DemoAppContext(DbContextOptions<DemoAppContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<User>(entity =>
{
entity.HasOne(d => d.UserDetail)
.WithOne(p => p.User)
.HasForeignKey<UserDetails>(x => x.UserId);
});
}
public DbSet<UserDetails> UserDetails { get; set; }
}
在Add-Migration
命令之后我收到此错误:
实体类型“UserDetails”需要定义主键。
正如我所说,如果我评论出Id
一切运作良好,但我不需要在PK
上的UserDetails
。
正如我所说,如果我注释掉Id一切正常,但我不需要在UserDetails上使用PK
如果我理解正确,你只是不想添加一个额外的列(例如,Id
或UserDetailsId
)设置为PK。您要创建的UserDetails
表将具有引用UserId
表的User
,并且UserId
将同时用作PK和FK。
实际上,没有必要为Id
实体提供UserDetails
属性。那么为什么你的代码不起作用呢?原因是您将依赖实体和主体实体混为一谈。
public virtual ReferenceReferenceBuilder<TEntity,TRelatedEntity> HasForeignKey<TDependentEntity>
(
Expression<Func<TDependentEntity,object>> foreignKeyExpression
)
where TDependentEntity : class;
请注意,HasForeignKey<TDependentEntity>()
的泛型参数表示从属实体。
这是你的代码:
builder.Entity<User>(entity =>
{
entity.HasOne(d => d.UserDetail)
.WithOne(p => p.User)
.HasForeignKey<UserDetails>(x => x.UserId);
});
看到了吗?在您的代码中,这里的entity
是User
,它是主要实体而不是从属实体。要解决此问题,请按以下方式更改代码:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<User>(entity =>
{
entity.HasOne(u => u.UserDetail).WithOne(d => d.User);
});
builder.Entity<UserDetails>(entity =>
{
// set the UserId as key
entity.HasKey(d=>d.UserId);
// the relationship between `UserDetails : User` is 1-to-1
entity.HasOne(d=>d.User).WithOne(u=>u.UserDetail)
// set column `UserId` as the FK for the dependent entity , i.e. , the `UserDetails` .
.HasForeignKey<UserDetails>(u=>u.UserId);
});
}
它将生成一个UserDetails
表,其中UserId
列同时设置为PrimaryKey和ForeignKey:
CREATE TABLE [dbo].[UserDetails] (
[Biography] NVARCHAR (MAX) NULL,
[Country] NVARCHAR (MAX) NULL,
[FacebookLink] NVARCHAR (MAX) NULL,
[TwitterLink] NVARCHAR (MAX) NULL,
[SkypeLink] NVARCHAR (MAX) NULL,
[UserId] NVARCHAR (450) NOT NULL,
CONSTRAINT [PK_UserDetails] PRIMARY KEY CLUSTERED ([UserId] ASC),
CONSTRAINT [FK_UserDetails_AspNetUsers_UserId] FOREIGN KEY ([UserId]) REFERENCES [dbo].[AspNetUsers] ([Id]) ON DELETE CASCADE
);
顺便说一句,Visual Studio的SQL Server对象资源管理器中似乎存在一个错误(请参阅my question here),导致我们无法看到已存在的FK禁区的错误。
但是,我们可以通过尝试插入具有不存在的UserId的行来证明它:
insert into UserDetails
(Biography,UserId)
values
('hello,wrold','here-is-a-non-existing-user-id')
它会按预期抱怨以下消息:
Msg 547,Level 16,State 0,Line 1
INSERT语句与FOREIGN KEY约束“FK_UserDetail_AspNetUsers_UserId”冲突。冲突发生在数据库“App-EFCore-FK-Test”,表“dbo.AspNetUsers”,列'Id'中。
该语句已终止。