2012-06-08 52 views
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个表创建 - 用户,角色和RoleUsers。

我知道我可以很容易做到以下

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() 

它将两个新角色保存到数据库中(分别给他们的1和2的角色ID值),新用户(给它一个用户ID值1)和一个RoleId 1和UserId 1的新角色 - 用户条目。

但是,当处理像网站这样的断开连接的情况时,大多数人会有一个View Model来表示来自用户的输入,映射回实体。另外,对于表示角色的值,返回的数据很可能只包含代表角色的唯一键。例如,

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()方法时,由于.RoleName属性为Nothing,EF会引发验证错误。

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

我知道这是很长,但我认为穿行会有帮助......

感谢。

+0

我第一次看到基本的EF代码。 –

+0

第一个代码是4.1及以上。 –

回答

1

您可以使用此算法

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

    子实体...

  • 保存并应用更改

如果你有一个非空的导航的实体已经存在于数据库中,并且尚未通过上下文访问,您可以通过ID设置关系(假设您已将FK映射到mo中的属性del)而不是设置实体本身。

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

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

+0

我不确定我了解您的回复。首先,我认为EDMX文件与原始实体框架相关联?我正在使用Code-First方法。但关于你的建议,你是否基本上说我不能使用映射程序(如AutoMapper)将我的网页视图模型转换为我的实体?我必须手动循环遍历所有视图模型对象(包括子对象)并在保存之前将它们与实体合并? – Jason

+0

1.即使最新版本的EF也可以有EDMX。如果您使用的是代码优先(您应该在问题中使用[tag:code-first]标签),那么同样适用,只有您必须通过代码而不是通过配置来执行所有操作。 –

+0

2.您可以使用映射代码,例如ValueInjector或AutoMapper。你必须确保你注入写入的东西。如果你使用的是AutoMapper,那么它自己创建对象(ValueInjector接收它们作为输入,因此它更灵活)。由于Automapper创建对象,因此必须使用全新的上下文,以便在上下文中不会有相同的实体两次(如果您已经通过上下文访问实体)。你也应该添加一个[tag:automapper]标签。 –