powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM [игнор отключен] [закрыт для гостей] / NHibernate - вопрос по ассоциации
1 сообщений из 1, страница 1 из 1
NHibernate - вопрос по ассоциации
    #35978866
SergASh
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Привет всем!

Есть две таблицы, связанные через ассоциацию:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
CREATE TABLE tbl_foo
(
  foo_id INT NOT NULL IDENTITY
 ,foo_payload VARCHAR( 100 ) NOT NULL
 ,CONSTRAINT PK__foo
    PRIMARY KEY ( foo_id )
)
CREATE TABLE tbl_bar
(
  bar_id INT NOT NULL IDENTITY
 ,bar_payload VARCHAR( 100 ) NOT NULL
 ,CONSTRAINT PK__bar
    PRIMARY KEY ( bar_id )
)
CREATE TABLE tbl_foo_bar
(
  foo_id INT NOT NULL
 ,bar_id INT NOT NULL
 ,foo_bar_payload VARCHAR( 100 ) NOT NULL
 ,CONSTRAINT PK__foo_bar
    PRIMARY KEY ( foo_id, bar_id )
 ,CONSTRAINT FK__foo_bar__foo
    FOREIGN KEY ( foo_id )
      REFERENCES tbl_foo ( foo_id )
      ON UPDATE CASCADE ON DELETE CASCADE
 ,CONSTRAINT FK__foo_bar__bar
    FOREIGN KEY ( bar_id )
      REFERENCES tbl_bar ( bar_id )
      ON UPDATE CASCADE ON DELETE CASCADE
)
INSERT INTO tbl_foo ( foo_payload )
            SELECT 'Foo 1' 
  UNION ALL SELECT 'Foo 2' 
  UNION ALL SELECT 'Foo 3'
INSERT INTO tbl_bar ( bar_payload )
            SELECT 'Bar 1' 
  UNION ALL SELECT 'Bar 2' 
  UNION ALL SELECT 'Bar 3'
INSERT INTO tbl_foo_bar ( foo_id, bar_id, foo_bar_payload )
            SELECT  1 ,  1 , 'Foo 1 - Bar 1' 
  UNION ALL SELECT  1 ,  2 , 'Foo 1 - Bar 2' 
  UNION ALL SELECT  1 ,  3 , 'Foo 1 - Bar 3' 
  UNION ALL SELECT  2 ,  2 , 'Foo 2 - Bar 2' 
  UNION ALL SELECT  2 ,  3 , 'Foo 2 - Bar 3' 

Ассоциация не имеет суррогатного ключа и добавлять его нельзя. Задача стоит построить такой маппинг, который бы позволил мне изменять значение foo_id или bar_id в таблице tbl_foo_bar, причем делать это с помощью операции UPDATE. Удалить запись и добавить другую не подходит, поскольку есть другие таблицы (здесь для краткости не показаны), которые ссылаются на tbl_foo_bar, и если запись удалится, то в этих связанных таблицах каскадно удалятся нужные данные.

Вот на какие классы делается отображение:

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
[Serializable]
public class Foo
{
  public Foo()
  {
  }

  #region Proprties
  public virtual long Id { get; set; }
  public virtual string Payload { get; set; }
  public virtual ISet<FooBar> FooBars
  {
    get
    {
      return fooBars_;
    }
    set
    {
      fooBars_ = value;
    }
  }
  private ISet<FooBar> fooBars_ = new HashedSet<FooBar>();
  #endregion // Proprties

  #region Equaltiy
  public virtual bool Equals( Foo obj )
  {
    if ( ReferenceEquals( null, obj ) ) return false;
    if ( ReferenceEquals( this, obj ) ) return true;
    return Equals( obj.Payload, Payload );
  }
  public override bool Equals( object obj )
  {
    if ( ReferenceEquals( null, obj ) ) return false;
    if ( ReferenceEquals( this, obj ) ) return true;
    if ( obj.GetType() != typeof( Foo ) ) return false;
    return Equals( (Foo)obj );
  }
  public override int GetHashCode()
  {
    return ( Payload != null ? Payload.GetHashCode() : 0 );
  }
  #endregion // Equaltiy

}
[Serializable]
public class Bar
{
  #region Construction
  public Bar()
  {
  }
  #endregion // Construction

  #region Proprties
  public virtual long Id { get; set; }
  public virtual string Payload { get; set; }
  public virtual ISet<FooBar> FooBars
  {
    get
    {
      return fooBars_;
    }
    set
    {
      fooBars_ = value;
    }
  }
  private ISet<FooBar> fooBars_ = new HashedSet<FooBar>();
  #endregion // Proprties

  #region Equaltiy
  public virtual bool Equals( Bar obj )
  {
    if ( ReferenceEquals( null, obj ) ) return false;
    if ( ReferenceEquals( this, obj ) ) return true;
    return Equals( obj.Payload, Payload );
  }
  public override bool Equals( object obj )
  {
    if ( ReferenceEquals( null, obj ) ) return false;
    if ( ReferenceEquals( this, obj ) ) return true;
    if ( obj.GetType() != typeof( Bar ) ) return false;
    return Equals( (Bar)obj );
  }
  public override int GetHashCode()
  {
    return ( Payload != null ? Payload.GetHashCode() : 0 );
  }
  #endregion // Equaltiy

}
public class FooBar
{
  [Serializable]
  public class Key
  {
    #region Construction
    public Key()
    {
    }
    public Key( Foo foo, Bar bar )
    {
      Foo = foo;
      Bar = bar;
    }
    #endregion // Construction

    #region Equality
    public bool Equals( Key obj )
    {
      if ( ReferenceEquals( null, obj ) ) return false;
      if ( ReferenceEquals( this, obj ) ) return true;
      return Equals( obj.Foo, Foo ) && Equals( obj.Bar, Bar );
    }
    public override bool Equals( object obj )
    {
      if ( ReferenceEquals( null, obj ) ) return false;
      if ( ReferenceEquals( this, obj ) ) return true;
      return obj.GetType() == typeof( Key ) && Equals( (Key)obj );
    }
    public override int GetHashCode()
    {
      unchecked
      {
        return ( ( Foo != null ? Foo.GetHashCode() : 0 ) * 397 ) ^ ( Bar != null ? Bar.GetHashCode() : 0 );
      }
    }
    #endregion // Equality

    public Foo Foo { get; set; }
    public Bar Bar { get; set; }
  }

  #region Construction
  public FooBar()
  {
  }
  #endregion // Construction

  #region Proprties
  public virtual Key Id { get; set; }
  public virtual string Payload { get; set; }
  #endregion // Proprties
}

А вот само отображение

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  
  <class name="ARR.Core.Domain.Test.Foo, ARR.Core" table="tbl_foo">
    <id name="Id" column="foo_id" unsaved-value="0">
      <generator class="identity" />
    </id>
    <property name="Payload" column="foo_payload"/>
    <set name="FooBars" table="tbl_foo_bar">
      <key column="foo_id"/>
      <one-to-many class="ARR.Core.Domain.Test.FooBar, ARR.Core"/>
    </set>
  </class>
  
  <class name="ARR.Core.Domain.Test.Bar, ARR.Core" table="tbl_bar">
    <id name="Id" column="bar_id" unsaved-value="0">
      <generator class="identity" />
    </id>
    <property name="Payload" column="bar_payload"/>
    <set name="FooBars" table="tbl_foo_bar">
      <key column="bar_id"/>
      <one-to-many class="ARR.Core.Domain.Test.FooBar, ARR.Core"/>
    </set>
  </class>
  
  <class name="ARR.Core.Domain.Test.FooBar, ARR.Core" table="tbl_foo_bar">
    <composite-id name="Id" class="ARR.Core.Domain.Test.FooBar+Key, ARR.Core" >
      <key-many-to-one name="Foo" column="foo_id" class="ARR.Core.Domain.Test.Foo, ARR.Core" />
      <key-many-to-one name="Bar" column="bar_id" class="ARR.Core.Domain.Test.Bar, ARR.Core" />
    </composite-id>
    <property name="Payload" column="foo_bar_payload"/>    
  </class>

</hibernate-mapping>

Используется так

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
var session = NHibernateSessionManager.Instance.GetSession();

var foo = session.Get<Foo>( 2L );
var bar = session.Get<Bar>( 3L );
var newBar = session.Get<Bar>( 1L );

var key = new FooBar.Key( foo, bar );
var fooBar = session.Get<FooBar>( key );

// Modify association record
fooBar.Payload = "Modified Payload";
fooBar.Id.Bar = newBar;

session.Save( fooBar );

Это не работает, поскольку NHibernate не знает, что раньше ключ был другим. Поэтому пытается обновить запись по ключу (foo_id=2, bar_id=1), которой в базе нет. Вот запись из лога
Код: plaintext
1.
2.
3.
4.
5.
 12 : 48 : 42  [ 9 ] DEBUG NHibernate.SQL - 
UPDATE dbo.tbl_foo_bar 
SET foo_bar_payload = @p0 
WHERE foo_id = @p1 AND bar_id = @p2
;
@p0 = 'Modified Payload', @p1 = '2', @p2 = '1'

А я хотел бы увидеть такое
Код: plaintext
1.
2.
3.
4.
UPDATE dbo.tbl_foo_bar 
SET foo_bar_payload = @p0, bar_id = @p1 
WHERE foo_id = @p2 AND bar_id = @p3
; 
@p0 = 'Modified Payload', @p1 = '1', @p2 = '2', @p3 = '3'

Спасибо.
...
Рейтинг: 0 / 0
1 сообщений из 1, страница 1 из 1
Форумы / ADO.NET, LINQ, Entity Framework, NHibernate, DAL, ORM [игнор отключен] [закрыт для гостей] / NHibernate - вопрос по ассоциации
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]