简体   繁体   English

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

[英]How to do a fluent nhibernate one to one mapping?

How do I do this I am trying to make a one to one mapping. 我该怎么做我试图做一对一的映射。

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

}

// class map //类地图

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

// student map //学生地图

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

Now every time I try to create a settings object and save it to the database it crashes. 现在,每当我尝试创建一个设置对象并将其保存到数据库时,它就会崩溃。

   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.

What am I missing? 我错过了什么?

Edit 编辑

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

I get these error for both ways 我两种方式都有这些错误

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

There are two basic ways how to map bidirectional one-to-one association in NH. 如何在NH中映射双向一对一关联有两种基本方法。 Let's say the classes look like this: 让我们说这些类看起来像这样:

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

Setting class is a master in the association ("aggregate root"). 设置类是关联中的主(“聚合根”)。 It is quite unusual but it depends on problem domain... 这很不寻常,但这取决于问题领域......

Primary key association 主键关联

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

and a new setting instance should be stored: 并应存储一个新的设置实例:

        var setting = new Setting();

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

        session.Save(setting);

Foreign key association 外键关联

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

Primary key association is close to your solution. 主键关联与您的解决方案很接近。 Primary key association should be used only when you are absolutely sure that the association will be always one-to-one. 只有当您完全确定关联始终是一对一时,才应使用主键关联。 Note that AllDeleteOrphan cascade is not supported for one-to-one in NH. 请注意,NH中的一对一不支持AllDeleteOrphan级联。

EDIT: For more details see: 编辑:有关详细信息,请参阅:

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

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

Here a complete sample with foreign key association 这里有一个完整的外键关联样本

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

    }
}

And the SQL to create tables 和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]);

First, define one of the sides of the relationship as Inverse(), otherwise there is a redundant column in the database and this may cause the problem. 首先,将关系的一侧定义为Inverse(),否则数据库中存在冗余列,这可能会导致问题。

If this doesn't work, output the SQL statements generated by NHibernate (using ShowSql or through log4net) and try to understand why the foreign key constraint is violated (or post it here with the SQL, and don't forget the values of the bind variables that appear afer the SQL statement). 如果这不起作用,输出由NHibernate生成的SQL语句(使用ShowSql或通过log4net)并尝试理解为什么违反外键约束(或在此处使用SQL发布它,并且不要忘记绑定在SQL语句之后出现的变量。

You should not define the StudentId in Sesstings class. 您不应该在Sesstings类中定义StudentId。 Sessting class already has it (from public virtual Student Student { get; set; } ). Sessting类已经拥有它(来自public virtual Student Student { get; set; } )。 Probably it should be SesstingId and you should map the Id field as well (you have to define/map the primary key). 可能它应该是SesstingId,你也应该映射Id字段(你必须定义/映射主键)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM