Map One-To-One Relationship Doesn't Allow Inserting
I'm trying to setup a one-to-one mapping from my Users to the UserDetails table. Say I have the following tables in my database:
Users:
- UserID (PK, Identity)
- UserName
- Password
UsersDetails:
- UserID (PK, FK)
- FirstName
- LastName
I have created the following poco classes:
public class User {
public virtual int UserID { get; set; }
public virtual string UserName { get; set; }
public virtual string Password { get; set; }
public virtual UserDetails Details { get; set; }
}
public class UserDetails {
public virtual int UserID { get; set; }
public virtual User User { get; set; }
public vi开发者_Python百科rtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public UserDetails() {
}
public UserDetails(User user) {
User = user;
}
}
Which are fluently mapped (please note the xml mapping is very similar and if all you know is the xml mapping then I would still appreciate you guidance):
public class UserMap : ClassMap<User> {
public UserMap() {
Table("Users");
Id(x => x.UserID);
Map(x => x.UserName);
Map(x => x.Password);
HasOne(x => x.Details)
.Constrained()
.Cascade.All();
}
}
public class UserDetailsMap : ClassMap<UserDetails> {
public UserDetailsMap() {
Table("UsersDetails");
Id(x => x.UserID)
.GeneratedBy.Foreign("User");
HasOne(x => x.User)
.Constrained();
Map(x => x.FirstName);
Map(x => x.LastName);
}
}
Everything displays correctly but if I say:
var user = new User() { UserName = "Test", Password = "Test" };
user.Details = new UserDetails(user) { FirstName = "Test", LastName = "Test" };
session.Save(user);
I get the error:
"NHibernate.Id.IdentifierGenerationException: null id generated for: UserDetails."
I'd really appreciate it if someone could show me what I've done wrong. Thanks
Edit: Courtesy of Jamie Ide's suggestion. I have changed my User mapping to:
public class UserMap : ClassMap<User> {
public UserMap() {
Table("Users");
Id(x => x.UserID);
Map(x => x.UserName);
Map(x => x.Password);
References(x => x.Details, "UserID")
.Class<UserDetails>()
.Unique();
}
}
But now when i insert a user i get the error:
"System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection."
If i add Cascade.All() on to my Reference i receive the original error i was getting about the null id generated.
I think Constrained
should only be specified in the UserDetailsMap, not in the UserMap. Try:
public class UserMap : ClassMap<User> {
public UserMap() {
Table("Users");
Id(x => x.UserID);
Map(x => x.UserName);
Map(x => x.Password);
HasOne(x => x.Details)
.Cascade.All();
}
}
EDIT:
See this and this. It appears that you have to map the relationship as many-to-one from the User side and one-to-one constrained from the UserDetails side to get lazy loading working with one-to-one. I don't know if this is different in NH3.
I am not sure the way you are mapping the ID property is correct. shouldnt it just be an autoincremented id and your mapping should be as follows:
Id(x=>x.UserId);
I dont know the idea behind using Foreign and how it fits into things here.. can you please illustrate the logic behind that?
I think you need to have the foreign key identity mapping in your User mapping instead of the UserDetails and the native one in the UserDetails. I have been unable to find a reference for it, though.
http://gorbach.wordpress.com/2010/09/24/fluent-onetoone/
HasOne(x => x.Details).Cascade.All().ForeignKey("UserDetails");
HasOne(x => x.User).Constrained();
var user = new User() { UserName = "Test", Password = "Test" };
user.Details = new UserDetails(user) { FirstName = "Test", LastName = "Test" };
user.Details.User = user;
session.Save(user);
After further research it appears that this won't work in version 2.0. I am now in a position to upgrade to version 3.0 where i believe this is now possible.
精彩评论