流利的休眠一对一映射
本文关键字:一对一 映射 休眠 | 更新日期: 2023-09-27 17:57:06
如何进行一对一映射。
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<Setting>("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<Student>
{
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
};
INSERT 语句与外键约束"FK_Settings_Students"冲突。冲突发生在数据库"数据库",表"dbo"中。学生","学生ID"列。该语句已终止。说明:执行当前 Web 请求期间发生未经处理的异常。请查看堆栈跟踪,了解有关错误及其在代码中起源位置的详细信息。
异常详细信息:System.Data.SqlClient.SqlException:INSERT 语句与 FOREIGN KEY 约束"FK_Settings_Students"冲突。冲突发生在数据库"数据库",表"dbo"中。学生","学生ID"列。该语句已终止。
我错过了什么?
编辑
public class StudentMap: ClassMap<Student>
{
public StudentMap()
{
Id(x => x.StudentId)
.GeneratedBy.Guid();
HasOne(x => x.Setting)
.PropertyRef("Student")
.Cascade.All();
}
}
public class SettingMap: ClassMap<Setting>
{
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();
}
}
<小时 /> Setting setting = new Setting
{
TimeZoneId = viewModel.SelectedTimeZone,
TimeZoneName = info.DisplayName,
EndOfTerm = DateTime.UtcNow.AddDays(-1),
Student = student
};
studentRepo.SaveSettings(setting);
studentRepo.Commit();
我两种方式都收到这些错误
计数 = 5 的此 SqlParameterCollection 的索引 5 无效。说明:执行当前 Web 请求期间发生未经处理的异常。请查看堆栈跟踪,了解有关错误及其在代码中起源位置的详细信息。
异常详细信息:System.IndexOutOfRangeException:计数 = 5 的此 SqlParameterCollection 的索引 5 无效。源错误:第 76 行:使用 (ITransaction 事务 = 会话。BeginTransaction()) 第 77 行:{ 第 78 行:事务。提交();第 79 行:} 第 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<Program>())
.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<Parent>(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<Child>
{
public ChildMap()
{
Table("ChildTable");
Id(x => x.Id).GeneratedBy.Native();
Map(x => x.Name);
References(x => x.Parent).Column("IdParent");
}
}
public class ParentMap : ClassMap<Parent>
{
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字段(你必须定义/映射主键)。