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

时间:2011-05-22 01:57:06

标签: c# nhibernate fluent-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<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
                                          };

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<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();
    }
}

// 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:         }

4 个答案:

答案 0 :(得分:37)

如何在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

答案 1 :(得分:3)

这是一个带有外键关联的完整示例

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]);

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

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