2009-07-22 8 views
1

Je suppose que nhibernate peut gérer des problèmes de références circulaires car je n'ai pas vu cela autrement mentionné dans les docs ou sur google (mais peut-être que j'ai les mauvais termes).comment puis-je faire nhibernate cascade enregistrer un ensemble d'objets avec des références circulaires?

suppose que j'ai une classe qui a en tant que membre d'une référence à une instance de lui-même:

par exemple

class A 
{ 
    A Other; 
} 

je puis créer 2 objets et demandez-leur d'une référence croisée autre

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

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

Je veux produire un ensemble d'applications pour ces classes telles que si je tente de sauver une dans une session, sauvera aussi b de telle sorte que la référence de b à a soit conservée.

Au moment j'ai produit une cartographie simple en utilisant le nombre à une association (en fait cela est généré par Fluent NHibernate, mais il semble OK sur l'inspection manuelle)

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

Mais quand je sauve, a1 ne sauvegarde pas la référence à a2 dans la base de données. Comment puis-je le faire faire cela?

exemple de code utilisant nhibernate couramment est ici (nhibernate, fluent-nhibernate et nunit - si les gens veulent une version dépouillée faites le moi savoir).

J'ai également créé un objet a3 qui se réfère à lui-même et cela ne sauvegarde pas comme je le voudrais.

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


    } 
} 

Répondre

4

Toujours effectuer votre INSERT/UPDATE dans une transaction. Voici un exemple de travail utilisant 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

Merci darin. C'est ce que j'ai pour faire des suppositions stupides sur les sessions. – fostandy

Questions connexes