流利的休眠一对一映射

本文关键字:一对一 映射 休眠 | 更新日期: 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字段(你必须定义/映射主键)。