Entity framework 4 在实体框架中仅使用外键保存引用属性

Entity framework 4 在实体框架中仅使用外键保存引用属性,entity-framework-4,ef-code-first,Entity Framework 4,Ef Code First,我肯定这个问题以前被问过,所以我提前道歉,但我不确定搜索中包含的关键词是否正确 当对象的一个属性是断开连接的环境(如网站)中的其他属性集合时,我很难理解更新(甚至插入)对象的正确模式。我的问题与web应用程序只返回id集合而不是完整对象的想法有关。我认为最好的解释方法是使用代码片段 给定以下对象 Public Class User Public Property UserId As Integer Public Property Username As String Public P

我肯定这个问题以前被问过,所以我提前道歉,但我不确定搜索中包含的关键词是否正确

当对象的一个属性是断开连接的环境(如网站)中的其他属性集合时,我很难理解更新(甚至插入)对象的正确模式。我的问题与web应用程序只返回id集合而不是完整对象的想法有关。我认为最好的解释方法是使用代码片段

给定以下对象

Public Class User
  Public Property UserId As Integer
  Public Property Username As String
  Public Property Roles As ICollection(Of Role)
End Class

Public Class Role
  Public Property RoleId As Integer
  Public Property RoleName As String
  Public Property Users As ICollection(OF User)
End Class

Public Class EFDbContext
  Inherits Entity.DbContext

  Public Property Users As Entity.DbSet(Of User)
  Public Property Roles As Entity.DbSet(Of Role)
End Class
数据库由3个表创建-用户、角色和角色扮演者

我知道我可以很容易地做到以下几点

Dim db = New EFDbContext()

Dim r1 = New Role() With { .RoleName = "User" }
Dim r2 = New Role() With { .RoleName = "Admin" }

db.Roles.Add(r1)
db.Roles.Add(r2)

Dim u1 = New User() With { .UserName = "test1", .Roles = New List(Of Role) }
u1.Roles.Add(r1)

db.Users.Add(u1)

db.SaveChanges()
它会将两个新角色(分别为RoleId值1和2)、一个新用户(为其提供UserId值1)和一个RoleId为1和UserId为1的新角色用户条目保存到数据库中

然而,当处理像网站这样的断开连接的场景时,大多数人都会有一个视图模型来表示用户的输入,然后映射回实体。此外,对于表示角色的值,返回的数据很可能只包含表示角色的唯一键。比如说,

Public Class UpdatedUserViewModel
  Public Property UserId As Integer
  Public Property Username As String
  Public Property RoleIds As ICollection(Of Integer)
End Class

...
...

Dim userEntity = db.Users.Find(user.Values.UserId)
AutoMapper.Mapper.Map(userValues, userEntity)
因此,虽然userEntity.Roles集合可能包含单个项,但映射程序可能只是添加了如下内容的条目

ForMember(Function(u) u.Roles, Sub(m) m.MapFrom(Function(su) su.RoleIds.Select(Function(r) New Role() With {.RoleId = r})))
现在我们来讨论这个问题,当调用
SaveChanges()
方法时,EF抛出一个验证错误,因为.RoleName属性为Nothing

这种情况如何处理?我们应该手动循环角色并从数据库中获取每个角色吗?我们不能使用映射工具吗?我是否为“缺失”属性提供假值,然后循环并将其标记为未更改

我知道这很长,但我认为走一遍会有帮助


谢谢。

您可以使用此算法

  • 从根实体开始。
    • 对于每个根实体,例如a类型的a,设置a的属性(导航属性除外)(至少所有必需属性(非空))
    • 将As添加到上下文中
  • 下一步准备子实体(必须正好有1个A的实体),例如b类型的b。
    • 设置b的属性(导航除外,至少所有非Nullable)
    • 对于每个b,将b添加到其a(例如a.Children.add(b))
  • 继续上面的子实体

  • 保存并应用更改

如果数据库中已存在具有不可为空导航的实体,且该实体尚未通过上下文访问,则可以按ID设置关系(假设已将FK映射到模型中的属性),而不是设置实体本身

如果您的ID不是存储生成的,请确保您也设置了它们。如果是,请确保将其定义为在EDMX中生成的存储


如果数据库中有FK,请确保EDMX知道这些FK,以便以正确的顺序进行插入(或者如果使用Oracle,您可以尝试使用延迟约束,如果您愿意)。

您可以使用此算法

  • 从根实体开始。
    • 对于每个根实体,例如a类型的a,设置a的属性(导航属性除外)(至少所有必需属性(非空))
    • 将As添加到上下文中
  • 下一步准备子实体(必须正好有1个A的实体),例如b类型的b。
    • 设置b的属性(导航除外,至少所有非Nullable)
    • 对于每个b,将b添加到其a(例如a.Children.add(b))
  • 继续上面的子实体

  • 保存并应用更改

如果数据库中已存在具有不可为空导航的实体,且该实体尚未通过上下文访问,则可以按ID设置关系(假设已将FK映射到模型中的属性),而不是设置实体本身

如果您的ID不是存储生成的,请确保您也设置了它们。如果是,请确保将其定义为在EDMX中生成的存储


如果数据库中有FK,请确保EDMX知道这些FK,以便以正确的顺序插入(或者如果使用Oracle,您可以尝试使用延迟约束,如果您愿意)。

我第一次在Basic中看到EF代码。我第一次在Basic中看到EF代码。我不确定是否理解您的响应。首先,我认为EDMX文件与原始实体框架相关联?我使用的是代码优先的方法。但是关于你的建议,你基本上是说我不能使用映射程序(如AutoMapper)将我的网页视图模型转换为实体吗?我必须手动循环所有视图模型对象(包括子对象),并在保存之前将它们与实体合并?1。即使是最新版本的EF也可以使用EDMx。如果您首先使用代码(您应该使用问题中的标记),则同样适用,只是您必须通过代码而不是通过配置来完成所有操作。您可以使用映射代码,例如ValueInjector或AutoMapper。你必须确保你注入了写的东西。如果您使用的是AutoMapper,那么它会创建对象本身(ValueInjector将对象作为输入接收,因此它更灵活)。由于Automapper创建对象,因此必须使用新的上下文,这样就不会在上下文中有两次相同的实体(如果已经通过上下文访问了该实体)。你也应该添加一个标记。我想我明白了,所以我不需要像上面那样使用带有{.RoleId=r}的新角色(),我需要已经从数据库读取了我的角色集合,并在进行映射时执行类似的操作(从Role中的ro.RoleId=r.Single())。如果角色是新的,则执行New Role()并添加到con