1

我确定这个问题之前已经被问过,所以我提前道歉,但我不确定在我的搜索中包含正确的关键字......

当对象的一个​​属性是断开连接的环境(如网站)中其他属性的集合时,我无法理解更新(甚至插入)对象的正确模式。我的问题与 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 的新 Role-User 条目。

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

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。

这种情况如何处理?我们是否应该手动遍历角色并从数据库中获取每个角色?我们可以不使用绘图工具吗?我是否为“缺失”属性提供虚假值,然后遍历并将它们标记为未更改?

我知道这很长,但我认为演练会有所帮助......

谢谢。

4

1 回答 1

1

你可以使用这个算法

  • 从根实体开始。
    • 对于每个根实体,例如 A 类型的 a,设置 a 的属性,除了导航属性(至少所有必需的属性(不可为空))
    • 将 As 添加到上下文中。
  • 接下来准备子实体(必须恰好有 1 个 A 的实体),例如 B 类型的 b。
    • 设置 b 的属性(除了导航,至少所有不可为空)。
    • 对于每个 b,将 b 添加到其 a (egaChildren.Add(b))。
  • 继续上面的子实体

    ...

  • 保存并应用更改

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

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

如果数据库中有 FK,请确保 EDMX 知道它们,以便插入以正确的顺序发生(或者如果使用 Oracle,如果需要,您可以尝试使用延迟约束)。

于 2012-06-08T23:10:17.530 回答