2009-07-22 4 views
1

私はdocやGoogleで別段の言及が見られていないので、nhibernateが循環参照の問題を処理できると仮定しています。nhibernateカスケードは、循環参照を持つオブジェクトのセットを保存する方法はありますか?

私がメンバとして自身のインスタンスへの参照を持つクラスがあると仮定:

例えば

class A 
{ 
    A Other; 
} 

私はその後、私はセッションに保存しようとする場合、そのようなことを、これらのクラスのマッピングのセットを生成したい、それを2つのオブジェクトを作成し、それらを相互参照相互

A a1 = new A(); 
A a2 = new A(); 

a1.Other = a2; 
a2.Other = a1; 

を持っていますbへの参照が保持されるような方法でbを保存します。

は、現時点では私はmany-to-one関連使用して単純なマッピングを生産している(実際にはこれが流暢NHibernateはによって生成されますが、手動検査でOKになります)

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access=""> 
    <class name="hibernate.experiment.CircularRefQn+A, hibernate.experiment, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`A`" xmlns="urn:nhibernate-mapping-2.2"> 
    <id name="Id" type="Int32" column="Id"> 
     <generator class="identity" /> 
    </id> 
    <many-to-one cascade="all" name="Other" column="Other_id" /> 
    </class> 
</hibernate-mapping> 

をしかし、私は、A1を保存するときa2への参照をデータベースに保存しません。どうすればこのようにすることができますか?

流暢なnhibernateを使用しているサンプルコードはここにあります(nhibernate、fluent-nhibernate、nunitが必要です - もし人々が削除されたバージョンを知りたい場合)。

自分自身を参照するa3オブジェクトも作成しましたが、これは私が望むように保存しません。

using System.IO; 
using FluentNHibernate.Cfg; 
using FluentNHibernate.Mapping; 
using NHibernate.Tool.hbm2ddl; 
using NUnit.Framework; 

namespace hibernate.experiment 
{ 
    [TestFixture] 
    public class CircularRefQn 
    { 
     [Test] 
     public void Test() 
     { 
      var file = this.GetType().Name + ".db"; 
      if (File.Exists(file)) 
       File.Delete(file); 

      var fcfg = Fluently.Configure() 
       .Database(FluentNHibernate.Cfg.Db.SQLiteConfiguration.Standard 
           .UsingFile(file)) 
           .Mappings(m => 
           { 
            m.FluentMappings.Add(typeof(A.Map)); 
            m.FluentMappings.ExportTo("."); 
           }) 
           .ExposeConfiguration(cfg => new SchemaExport(cfg).Create(true, true)) 
       ; 

      var sFactory = fcfg.BuildSessionFactory(); 


      using (var s = sFactory.OpenSession()) 
      { 
       A a1 = new A(); 
       A a2 = new A(); 

       a1.Other = a2; 
       a2.Other = a1; 

       Assert.NotNull(a1.Other); 
       Assert.NotNull(a2.Other); 

       A a3 = new A(); 
       a3.Other = a3; 

       s.Save(a1); 
       s.Update(a1); 
       s.Save(a3); 
      } 

      using (var s = sFactory.OpenSession()) 
      { 
       foreach (var a in s.CreateCriteria(typeof(A)).List<A>()) 
        Assert.NotNull(a.Other); 
      } 
     } 

     public class A 
     { 
      public virtual int Id { get; set; } 
      public virtual A Other { get; set; } 

      public class Map : ClassMap<A> 
      { 
       public Map() 
       { 
        Id(x => x.Id); 
        References(x => x.Other) 
         .Cascade.All(); 
       } 
      } 
     } 


    } 
} 

答えて

4

トランザクション内で常にINSERT/UPDATEを実行します。 SQLiteを使用した実例があります:

using System; 
using System.Data; 
using System.IO; 
using FluentNHibernate.Cfg; 
using FluentNHibernate.Cfg.Db; 
using FluentNHibernate.Mapping; 
using NHibernate; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     if (File.Exists("data.db3")) 
     { 
      File.Delete("data.db3"); 
     } 

     using (var factory = CreateSessionFactory()) 
     { 
      // Create schema and insert sample data 
      using (var connection = factory.ConnectionProvider.GetConnection()) 
      { 
       ExecuteQuery("create table users(usr_id integer primary key, other_id int, usr_name string)", connection); 
      } 

      using (var session = factory.OpenSession()) 
      using (var tx = session.BeginTransaction()) 
      { 
       User u1 = new User() { Name = "User1" }; 
       User u2 = new User() { Name = "User2" }; 

       u1.Other = u2; 
       u2.Other = u1; 
       session.Save(u1); 
       tx.Commit(); 
      } 

      // Verify database state after inserts with ADO.NET 
      using (var connection = factory.ConnectionProvider.GetConnection()) 
      using (var command = connection.CreateCommand()) 
      { 
       command.CommandText = "select usr_id, other_id, usr_name from users"; 
       using (var reader = command.ExecuteReader()) 
       { 
        while (reader.Read()) 
        { 
         Console.WriteLine("usr_id: {0}, other_id: {1}, usr_name: {2}", reader.GetInt32(0), reader.GetInt32(1), reader.GetString(2)); 
        } 
       } 
      } 
     } 
    } 

    private static ISessionFactory CreateSessionFactory() 
    { 
     return Fluently.Configure() 
      .Database(
       SQLiteConfiguration.Standard.UsingFile("data.db3").ShowSql() 
      ) 
      .Mappings(
       m => m.FluentMappings.AddFromAssemblyOf<Program>() 
      ).BuildSessionFactory(); 
    } 

    static void ExecuteQuery(string sql, IDbConnection connection) 
    { 
     using (var command = connection.CreateCommand()) 
     { 
      command.CommandText = sql; 
      command.ExecuteNonQuery(); 
     } 
    } 
} 

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

public class UserMap : ClassMap<User> 
{ 
    public UserMap() 
    { 
     WithTable("users"); 
     Id(x => x.Id, "usr_id"); 
     Map(x => x.Name, "usr_name"); 
     References(x => x.Other) 
      .ColumnName("other_id") 
      .Cascade.All(); 
    } 
} 
+0

ありがとうございました。これは私がセッションについての愚かな仮定を作るために得るものです。 – fostandy

関連する問題