下午好 -
我正在使用LINQ to Entity Framework为数据访问层开发Silverlight应用程序。我的n层数据库模型包括大约30个左右的表,其中包含许多多层次的父子关系。最近开始编写我的数据服务和单元测试,并发现在已经定义父表记录时将新记录插入子表的问题。这是我的父表和子表的删节版本:
父母表:
用户的
用户ID(PK)
电子邮件
密码
等...
儿童表:
的UserProfiles 的
UserProfileID(PK)
各种简介信息...
UserID(FK - 用户表)
所以在这一点上,我已经使用Entity Framework为ORM创建了各种类,我希望为我的实体上的CRUD操作创建数据服务。以下是我的方法插入新用户(没有父表引用)的示例代码:
public User CreateUser(User newUser)
{
using (var _context = new ProjectDatabase())
{
newUser.CreatedDate = DateTime.Now;
newUser.ModifiedDate = DateTime.Now;
_context.AddToUsers(newUser);
_context.SaveChanges();
}
return newUser;
}
这很好用。我已经为它编写了单元测试,没问题。另一方面,现在考虑我编写的以下数据服务方法,以便将新的 UserProfile 对象插入到数据库中。首先,我有一个非常相似的数据服务:
public UserProfile CreateProfile(UserProfile newUserProfile)
{
using (var _context = new ProjectDatabase())
{
newUserProfile.CreatedDate = DateTime.Now;
newUserProfile.ModifiedDate = DateTime.Now;
_context.AddToUserProfiles(newUserProfile);
_context.SaveChanges();
}
return newUserProfile;
}
此代码与其他代码一样,编译没有问题。但是,我的单元测试始终失败。这是我的单元测试的代码:
[TestMethod]
public void UserProfileCrudTest()
{
IProfileDataService _dataService = new ProfileDataService();
// Pre-seeded data on a State for foreign key
State _myState;
using (var _context = new ProjectDatabase())
{
_myState = _context.States.First();
}
// Creating temporary User for association with new UserProfile
User _myUser = new User()
{
Email = "test",
Password = "test",
IsActive = true,
NameFirst = "test",
NameLast = "test"
};
_myUser = _dataService.CreateUser(_myUser);
Assert.IsNotNull(_myUser);
// Attempt to create new UserProfile, assigning foreign key
_myUserProfile = new UserProfile()
{
Address = "123 Main",
City = "Anywhere",
State = _myState,
PostalCode = "63021",
UserID = _myUser.UserID
};
// This call to CreateProfile throws an exception and the test fails!!
_myUserProfile = _dataService.CreateProfile(_myUserProfile);
Assert.IsNotNull(_myUserProfile);
// Remaining test code... never gets this far...
}
所以在这一点上,我的单元测试引发了以下异常:
测试方法MyProject.DataServices.Tests.SecurityTests.UserProfileCrudTest抛出异常: System.InvalidOperationException :只有当属性的当前值为null时,才能设置EntityKey属性。
正如我从目前为止的研究中所理解的那样,这在某种程度上回到了导航属性,该属性将新的UserProfile对象与父表/对象上的User.UserProfiles集合相关联。但我不确定解决问题需要哪些步骤。我是否需要将父级附加到ObjectContext?任何帮助都会非常感激!
谢谢, 杰夫S。
答案 0 :(得分:7)
你不需要做那些事情。使用EF 4.0,您的代码可以像这样简单:
public UserProfile Create(UserProfile userProfile) {
using (var context = new ProjectDatabase()) {
//add the new graph to the context:
context.UserProfiles.AddObject(userProfile);
context.SaveChanges();
}
return userProfile;
}
public void UserProfileCrudTest() {
User _myUser = new User() {
Email = "test",
...
};
UserProfile _myUserProfile = new UserProfile() {
Address = "123 Main",
...
};
// join the new UserProfile to the User
_myUserProfile.User = _myUser;
UserProfile userProfile = Create(_myUserProfile);
}
在典型的数据访问方案中,您所做的是有意义的,您必须首先插入新的用户,检索其 UserID ,然后使用它来插入新的 UserProfile 。但是, SaveChanges 会在看到两者时为您完成所有这些操作
是新的,他们是相关的。它还使用模型的映射来确定哪些
是依赖实体(在本例中为UserProfile)并且需要外键(UserID)。
使用此信息,它以正确的顺序执行数据库插入。
向现有用户添加新的UserProfile:
如果要向现有用户添加新的UserProfile,并且您已经拥有要添加配置文件的User对象,则可以通过编写以下内容来关联它们:
userProfile.User = yourUserObject
// OR
yourUserObject.UserProfiles.add(userProfile)
然后调用SavingChanges()。
如果您只有UserID,则可以像UserProfile.UserID = userID一样设置它。顺便说一句,我知道这是你最初尝试做的事情,你有一个例外,所以这是你需要做的:
1.从数据库更新模型,以确保模型与数据库完全同步。
2.逐步执行代码并确保将正确的UserID设置为UserProfile对象(用户表中确实存在的东西) - 您甚至可以尝试对其进行硬编码。
3.再次运行它,如果你仍然遇到异常,那么请发布你的堆栈跟踪,因为我运行了你的代码而我没有得到任何代码,所以你的异常可能来自一个完全不同的问题。