如何做一个流利的nhibernate一对一映射?

我该怎么做我试图进行一对一的映射。

public class Setting { public virtual Guid StudentId { get; set; } public virtual DateFilters TaskFilterOption { get; set; } public virtual string TimeZoneId { get; set; } public virtual string TimeZoneName { get; set; } public virtual DateTime EndOfTerm { get; set; } public virtual Student Student { get; set; } } 

//类地图

  public SettingMap() { /// Id(Reveal.Member("StudentId")).GeneratedBy.Foreign("StudentId"); //Id(x => x.StudentId); Map(x => x.TaskFilterOption).Default(DateFilters.All.ToString()).NvarcharWithMaxSize().Not.Nullable(); Map(x => x.TimeZoneId).NvarcharWithMaxSize().Not.Nullable(); Map(x => x.TimeZoneName).NvarcharWithMaxSize().Not.Nullable(); Map(x => x.EndOfTerm).Default("5/21/2011").Not.Nullable(); HasOne(x => x.Student); } 

//学生地图

 public class StudentMap : ClassMap { public StudentMap() { Id(x => x.StudentId); HasOne(x => x.Setting).Cascade.All(); } } public class Student { public virtual Guid StudentId { get; private set; } public virtual Setting Setting { get; set; } } 

现在,每当我尝试创建一个设置对象并将其保存到数据库时,它就会崩溃。

  Setting setting = new Setting { TimeZoneId = viewModel.SelectedTimeZone, TimeZoneName = info.DisplayName, EndOfTerm = DateTime.UtcNow.AddDays(-1), Student = student }; The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Settings_Students". The conflict occurred in database "Database", table "dbo.Students", column 'StudentId'. The statement has been terminated. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. Exception Details: System.Data.SqlClient.SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Settings_Students". The conflict occurred in database "Database", table "dbo.Students", column 'StudentId'. The statement has been terminated. 

我错过了什么?

编辑

 public class StudentMap : ClassMap { public StudentMap() { Id(x => x.StudentId).GeneratedBy.Guid(); HasOne(x => x.Setting).PropertyRef("Student").Cascade.All(); } } public class SettingMap : ClassMap { public SettingMap() { Id(x => x.StudentId).GeneratedBy.Guid(); Map(x => x.TaskFilterOption).Default(DateFilters.All.ToString()).NvarcharWithMaxSize().Not.Nullable(); Map(x => x.TimeZoneId).NvarcharWithMaxSize().Not.Nullable(); Map(x => x.TimeZoneName).NvarcharWithMaxSize().Not.Nullable(); Map(x => x.EndOfTerm).Default("5/21/2011").Not.Nullable(); References(x => x.Student).Unique(); } } // try 1 Setting setting = new Setting { TimeZoneId = viewModel.SelectedTimeZone, TimeZoneName = info.DisplayName, EndOfTerm = DateTime.UtcNow.AddDays(-1), Student = student }; studentRepo.SaveSettings(setting); studentRepo.Commit(); // try 2 Setting setting = new Setting { TimeZoneId = viewModel.SelectedTimeZone, TimeZoneName = info.DisplayName, EndOfTerm = DateTime.UtcNow.AddDays(-1), Student = student }; student.Setting = setting studentRepo.CreateStudent(student); studentRepo.Commit(); 

我两种方式都有这些错误

 Invalid index 5 for this SqlParameterCollection with Count=5. Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. Exception Details: System.IndexOutOfRangeException: Invalid index 5 for this SqlParameterCollection with Count=5. Source Error: Line 76: using (ITransaction transaction = session.BeginTransaction()) Line 77: { Line 78: transaction.Commit(); Line 79: } Line 80: } 

如何在NH中映射双向一对一关联有两种基本方法。 让我们说这些类看起来像这样:

 public class Setting { public virtual Guid Id { get; set; } public virtual Student Student { get; set; } } public class Student { public virtual Guid Id { get; set; } public virtual Setting Setting { get; set; } } 

设置类是关联中的主(“聚合根”)。 这很不寻常,但这取决于问题领域……

主键关联

 public SettingMap() { Id(x => x.Id).GeneratedBy.Guid(); HasOne(x => x.Student).Cascade.All(); } public StudentMap() { Id(x => x.Id).GeneratedBy.Foreign("Setting"); HasOne(x => x.Setting).Constrained(); } 

并应存储一个新的设置实例:

  var setting = new Setting(); setting.Student = new Student(); setting.Student.Name = "student1"; setting.Student.Setting = setting; setting.Name = "setting1"; session.Save(setting); 

外键协会

 public SettingMap() { Id(x => x.Id).GeneratedBy.Guid(); References(x => x.Student).Unique().Cascade.All(); } public StudentMap() { Id(x => x.Id).GeneratedBy.Guid(); HasOne(x => x.Setting).Cascade.All().PropertyRef("Student"); } 

主键关联与您的解决方案很接近。 只有当您完全确定关联始终是一对一时,才应使用主键关联。 请注意,NH中的一对一不支持AllDeleteOrphan级联。

编辑:有关详细信息,请参阅:

http://fabiomaulo.blogspot.com/2010/03/conform-mapping-one-to-one.html

http://ayende.com/blog/3960/nhibernate-mapping-one-to-one

这里有一个完整的外键关联样本

 using System; using FluentNHibernate.Cfg; using FluentNHibernate.Cfg.Db; using NHibernate; using FluentNHibernate.Mapping; namespace NhOneToOne { public class Program { static void Main(string[] args) { try { var sessionFactory = Fluently.Configure() .Database( MsSqlConfiguration.MsSql2005 .ConnectionString(@"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=NHTest;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False") .ShowSql() ) .Mappings(m => m .FluentMappings.AddFromAssemblyOf()) .BuildSessionFactory(); ISession session = sessionFactory.OpenSession(); Parent parent = new Parent(); parent.Name = "test"; Child child = new Child(); child.Parent = parent; parent.Child = child; session.Save(parent); session.Save(child); int id = parent.Id; session.Clear(); parent = session.Get(id); child = parent.Child; } catch (Exception e) { Console.Write(e.Message); } } } public class Child { public virtual string Name { get; set; } public virtual int Id { get; set; } public virtual Parent Parent { get; set; } } public class Parent { public virtual string Name { get; set; } public virtual int Id { get; set; } public virtual Child Child { get; set; } } public class ChildMap : ClassMap { public ChildMap() { Table("ChildTable"); Id(x => x.Id).GeneratedBy.Native(); Map(x => x.Name); References(x => x.Parent).Column("IdParent"); } } public class ParentMap : ClassMap { public ParentMap() { Table("ParentTable"); Id(x => x.Id).GeneratedBy.Native(); Map(x => x.Name); HasOne(x => x.Child).PropertyRef(nameof(Child.Parent)); } } } 

和SQL一起创建表

 CREATE TABLE [dbo].[ParentTable] ( [Id] INT IDENTITY (1, 1) NOT NULL, [Name] VARCHAR (MAX) NULL ); CREATE TABLE [dbo].[ChildTable] ( [Id] INT IDENTITY (1, 1) NOT NULL, [IdParent] INT NOT NULL, [Name] VARCHAR (50) NULL ); ALTER TABLE [dbo].[ChildTable] ADD CONSTRAINT [FK_ChildTable_ToTable] FOREIGN KEY ([IdParent]) REFERENCES [dbo].[ParentTable] ([Id]); 

首先,将关系的一侧定义为Inverse(),否则数据库中存在冗余列,这可能会导致问题。

如果这不起作用,输出由NHibernate生成的SQL语句(使用ShowSql或通过log4net)并尝试理解为什么违反外键约束(或在此处使用SQL发布它,并且不要忘记它的值绑定在SQL语句之后出现的变量。

您不应该在Sesstings类中定义StudentId。 Sessting类已经拥有它(来自public virtual Student Student { get; set; } )。 可能它应该是SesstingId,你也应该映射Id字段(你必须定义/映射主键)。