Jak zrobić płynne mapowanie NHibernate jeden do jednego?
Jak to zrobić staram się zrobić mapowanie jeden do jednego.
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; }
}
/ / Mapa klas
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);
}
// Mapa ucznia
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; }
}
Teraz za każdym razem, gdy próbuję utworzyć obiekt settings i zapisać go w bazie danych, ulega awarii.
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.
Co mi umyka?
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: }
4 answers
Istnieją dwa podstawowe sposoby mapowania dwukierunkowego powiązania jeden do jednego w NH. Powiedzmy, że klasy wyglądają tak:
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; }
}
Ustawianie klasy jest wzorcem w asocjacji ("zagregowany root"). Jest to dość nietypowe, ale zależy to od domeny problemu...
Asocjacja klucza głównego
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();
}
I powinna zostać zapisana nowa instancja ustawień:
var setting = new Setting();
setting.Student = new Student();
setting.Student.Name = "student1";
setting.Student.Setting = setting;
setting.Name = "setting1";
session.Save(setting);
Stowarzyszenie kluczy zagranicznych
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");
}
Podstawowe skojarzenie kluczy jest bliskie twojemu rozwiązaniu. Asocjacja klucza podstawowego powinna być używana tylko wtedy, gdy masz absolutną pewność, że Asocjacja będzie zawsze jeden do jednego. Zauważ, że kaskada AllDeleteOrphan nie jest obsługiwana dla one-to-one w NH.
EDIT: po więcej szczegółów zobacz:
Http://fabiomaulo.blogspot.com/2010/03/conform-mapping-one-to-one.html
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-22 10:10:23
Tutaj pełna próbka z asocjacją klucza obcego
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));
}
}
}
I SQL do tworzenia tabel
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]);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-08 20:25:20
Najpierw zdefiniuj jedną ze stron relacji jako Inverse (), w przeciwnym razie w bazie danych znajduje się nadmiarowa kolumna i może to spowodować problem.
Jeśli to nie zadziała, wypuść polecenia SQL wygenerowane przez NHibernate (używając ShowSql lub log4net) i spróbuj zrozumieć, dlaczego ograniczenie klucza obcego jest naruszone (lub opublikuj je tutaj z SQL i nie zapomnij o wartościach zmiennych bind, które pojawiają się po instrukcji SQL).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-22 03:25:33
Nie powinieneś definiować StudentId w klasie Sesstings. Klasa Sessting już ją ma (od
public virtual Student Student { get; set; }
). Prawdopodobnie powinien to być SesstingId i powinieneś mapować pole Id (musisz zdefiniować / mapować klucz główny).
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-05-22 04:46:13