代码优先EF5:一对零或一关系不起作用
本文关键字:关系 不起作用 代码 EF5 | 更新日期: 2023-09-27 18:25:38
类似的问题似乎都无法解决这个问题。我使用实体框架5,MVC 4,.NET 4.5作为我的web应用程序,使用VS 2012设计。
我有两个班,应该是亲子关系。
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
// Other stuff
public int? JoggerId { get; set; }
public virtual Jogger Jogger{ get; set; }
}
和
public class Jogger
{
[Key]
public int JoggerId { get; set; }
[Required, ForeignKey("UserId")]
public int UserId { get; set; }
public virtual UserProfile UserProfile { get; set; }
}
使用Fluent API:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<UserProfile>()
.HasOptional(x => x.Jogger)
.WithRequired(c => c.UserProfile)
.WillCascadeOnDelete(true);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
base.OnModelCreating(modelBuilder);
}
用户可以是慢跑者,但也可以不是慢跑者,即一个用户到零或一个慢跑者。在EF Powertools edmx视图中,关系看起来很好,但我无法获得外键来使用UserProfile UserId。
我的Fluent API是错的还是我的模型?请帮帮我,我真的被卡住了!
使用Fluent API进行映射是可以的,但从模型中删除UserProfile.JoggerId
和Jogger.UserId
属性,它应该可以工作。原因是Entity Framework使用Jogger
的主键作为UserProfile
的外键,因此您不需要(也不能)具有单独的外键属性。这种一对一的关系被称为"共享主键关联"。
编辑
请记住,Jogger
的主键(作为关系的依赖项)是而不是在数据库中自动生成的,只有UserProfile
的主键是自动生成的(作为关系主体)。
将UserProfile
或Jogger
或两者都插入数据库的方式如下:
-
如果您想插入一个没有
Jogger
的UserProfile
,只需将其添加到上下文中即可:using (var context = new MyContext()) { var newUserProfile = new UserProfile(); // no key needs to be supplied, the DB will take care context.UserProfiles.Add(newUserProfile); context.SaveChanges(); }
-
如果您想在一个步骤中插入带有
Jogger
的UserProfile
:using (var context = new MyContext()) { var newUserProfile = new UserProfile { Jogger = new Jogger() }; // no key needs to be supplied, neither for UserProfile // nor for Jogger, the DB will take care context.UserProfiles.Add(newUserProfile); context.SaveChanges(); }
-
如果要插入
Jogger
(对于现有的UserProfile
,它必须是Jogger
):using (var context = new MyContext()) { var newJogger = new Jogger { JoggerId = someExistingUserProfileId }; // a valid key needs to be supplied, otherwise you would violate a FK // constraint in the database context.Joggers.Add(newJogger); context.SaveChanges(); }
编辑2
对于您的用例,如果您没有直接可用的UserId
,而是Name
(作为已验证用户),则必须首先从数据库加载密钥或UserProfile
:
// we are in an ASP.NET MVC controller action here
using (var context = new MyContext())
{
string userName = User.Identity.Name;
int? userId = context.UserProfiles
.Where(u => u.Name == userName)
.Select(u => (int?)u.UserId)
.SingleOrDefault();
if (userId.HasValue)
{
var newJogger = new Jogger { JoggerId = userId.Value };
context.Joggers.Add(newJogger);
context.SaveChanges();
}
}
或者加载UserProfile
也可以:
using (var context = new MyContext())
{
string userName = User.Identity.Name;
UserProfile userProfile = context.UserProfiles
.Where(u => u.Name == userName)
.SingleOrDefault();
if (userProfile != null)
{
userProfile.Jogger = new Jogger();
// I believe you don't need to set the JoggerId key now,
// I'm not sure though
context.SaveChanges();
// Change tracking recognizes the new Jogger
// no context.Joggers.Add is required
}
}