Fluent Nhibernate как да зададете стойности за ненулеви колони по време на каскадно записване

Имам таблици със следната връзка:

public class Physicians
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual List<Specialty> Specialties{ get; set; }
    public virtual User CreatedBy { get; set; }
}

public class Specialties
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }    
    public virtual User CreatedBy { get; set; }
}


public class PhysicianSpecialtyBridge
{
   public virtual Physicians Physician{get; set;}
   public virtual Specialties Specialty { get; set; }
   public virtual User CreatedBy { get; set; }
}

В картографирането, което съм посочил като

 HasManyToMany(physician => physician.Specialties).Table("PhysicianSpecialty")
.ParentKeyColumn("Physician").ChildKeyColumn("Specialty").Cascade.All;

Проблемът, който имам, когато се опитвам да свържа лекаря със списъка със специалности и да направя запазване, се проваля, докато се опитвам да вмъкна в мостовата таблица, тъй като ключът createdby в PhysicianSpecialtyBridge не е нула. Когато направя колоната nullable, всичко работи добре. Някакво решение за този проблем? По някаква причина трябва да поддържам "CreatedBy" и в моята мостова таблица.




Отговори (1)


Проблемът тук е, че докато използвате many-to-many картографиране, C# Entities представляват различна връзка. Many-to-many се използва в сценарии, когато 1) имаме таблица за сдвояване, но 1) няма C# Entity за нейното представяне.

A) Бих предложил, ако искате да запазите обекта за сдвояване като C# обект, за да промените вашия модел. Трябва да е така:

1) Таблицата за сдвояване трябва да има собствен сурогатен ключ

public class PhysicianSpecialtyBridge
{
   // the pairing object should have the ID
   public virtual int Id { get; set; }
   public virtual Physician  Physician { get; set; }
   public virtual Speciality Speciality{ get; set; }
   ...

2) другият обект трябва да изброява обекта за сдвояване (ЗАБЕЛЕЖКА, че използвах единствено число за имена на обекти)

public class Physician
{
    ...
    public virtual List<PhysicianSpecialtyBridge> Specialties{ get; set; }


public class Specialty
{
    ...
    public virtual List<PhysicianSpecialtyBridge> Physicians{ get; set; }

Тогава картографирането на обекта за сдвояване ще бъде като

References( x => x.Physician);
References( x => x.Specialty);

Лекарите вече са във връзка one-to-many с обекта за сдвояване

HasMany(x => x.Specialties)
  .Inverse()
  .Cascade.All(); 

Специалностите са подобни

HasMany(x => x.Physicians)
  .Inverse()
  .Cascade.All(); 

B) Ако наистина искате много към много, тогава трябва да премахнете обекта за сдвояване. C# Entites ще бъде така:

public class Physician
{
    ...
    public virtual List<Specialty> Specialties{ get; set; }


public class Specialty
{
    ...
    public virtual List<Physician> Physicians{ get; set; }

И картографирането

Лекарите

HasManyToMany(x => x.Specialties)
  .Table("PhysicianSpecialty")
  .ParentKeyColumn("Specialty")
  .ChildKeyColumn("Physician")
  .Inverse()
  //.Cascade.All() - NO Cascade, pairing table will be managed by default
  ; 

Специалностите

HasManyToMany(x => x.Physicians)
  .Table("PhysicianSpecialty")
  .ParentKeyColumn("Physician")
  .ChildKeyColumn("Specialty")
  // .Inverse() - NOT INVERSE, only one can be
  // .Cascade.All() - NO Cascade, that will remove the Speciality
  ; 

Подходът А) е по-добър и се препоръчва. Едно от предимствата е, че вашият обект за сдвояване може да има повече свойства (напр. CreatedBy или Order ... IsActive)... и също така получавате възможността да търсите с подзаявки за лекари, имащи някакъв вид специалности

Моля, проверете Глава 24. Най-добри практики. Екстракт

Не използвайте екзотични съпоставяния на асоциации.

Добрите случаи на употреба за реални асоциации много към много са редки. През повечето време се нуждаете от допълнителна информация, съхранявана в „таблицата с връзки“. В този случай е много по-добре да използвате две асоциации "един към много" към клас междинна връзка. Всъщност смятаме, че повечето асоциации са едно към много и много към едно, трябва да внимавате, когато използвате друг стил на асоцииране и да се запитате дали наистина е необходим.

Също така можете да проверите Nhibernate: Как да представя релации много към много с релации един към много? за повече подробности за алтернативата на много към много. Някои четива за предимствата на подзаявките могат да бъдат намерени тук https://stackoverflow.com/a/14080092/1679310

person Radim Köhler    schedule 12.12.2013
comment
Благодаря за вашия отговор. Това, което не разбирам, е как ще се попълни колоната CreatedBy за таблицата Bridge. Има ли начин да кажа, използвайте CreatedBy от таблицата Physician, за да зададете CreatedBy в таблицата Bridge? - person Vinoth; 13.12.2013
comment
Има наистина повече начини. Едно може да бъде подобно, както предлагате... когато създадете специален метод AddSpeciality(speciality) и там можете да зададете правилно всички отношения и дори да използвате повторно createdby. Това, което предпочитам, е да създам шаблонен метод (образец), където да помолите вашето бизнес ниво да създаде обекта за сдвояване и там можете да попълните от вашия принципал, който е създател. Това е по-гъвкаво, защото не винаги създателят на лекаря е този, който разширява връзката с нова специалност. Но така или иначе, от моя опит бих искал да са във вашия персонализиран бизнес код - person Radim Köhler; 13.12.2013