2010-02-11 10 views
8

voglio fare esattamente ciò che a questa domanda si chiede: Cascade Saves with Fluent NHibernate AutoMappingCascade salva con Fluent NHibernate AutoMapping - Vecchia risposta ancora valida?

Utilizzando Fluent NHibernate Mapping per accendere "a cascata" a livello globale una volta per tutte le classi e tipi di relazione che utilizzano una chiamata piuttosto che impostare per ogni mapping singolarmente.

La risposta alla domanda precedente sembra ottima, ma temo che l'API Fluent Nhibernate abbia modificato la sua sintassi. ConConvention lo scorso anno e abbia rotto la risposta ... o quello o mi manca qualcosa.

continuo a ricevere un po 'di spazio dei nomi non trovato errori relativi alla IOneToOnePart, IManyToOnePart e tutti i loro varianti:

"Il tipo o dello spazio dei nomi il nome 'IOneToOnePart' non è stato trovato (che le manca una direttiva using o un riferimento all'assembly?) "

Ho provato le dll di esempio ufficiali, le dll di RTM e l'ultima build e nessuno di loro sembra che VS 2008 veda lo spazio dei nomi richiesto.

Il secondo problema è che voglio utilizzare la classe con il mio AutoPersistenceModel ma non sono sicuro dove questa linea: .ConventionDiscovery.AddFromAssemblyOf() nel mio metodo di creazione di fabbrica.

private static ISessionFactory CreateSessionFactory() 
      { 

       return Fluently.Configure() 
        .Database(SQLiteConfiguration.Standard.UsingFile(DbFile)) 
        .Mappings(m => m.AutoMappings 
         .Add(AutoMap.AssemblyOf<Shelf>(type => type.Namespace.EndsWith("Entities")) 
           .Override<Shelf>(map => 
           { 
            map.HasManyToMany(x => x.Products).Cascade.All(); 
           }) 
          ) 

        )//emd mappings 
       .ExposeConfiguration(BuildSchema) 
       .BuildSessionFactory();//finalizes the whole thing to send back. 

      } 

Di seguito le dichiarazioni di classe e utilizzando sto cercando

using System; 
    using System.Collections.Generic; 
    using System.Linq; 
    using System.Text; 
    using System.IO; 

    using FluentNHibernate.Conventions; 
    using FluentNHibernate.Cfg; 
    using FluentNHibernate.Cfg.Db; 
    using NHibernate; 
    using NHibernate.Cfg; 
    using NHibernate.Tool.hbm2ddl; 
    using FluentNHibernate.Mapping; 


    namespace TestCode 
    { 
     public class CascadeAll : IHasOneConvention, IHasManyConvention, IReferenceConvention 
     { 
      public bool Accept(IOneToOnePart target) 
      { 
       return true; 
      } 

      public void Apply(IOneToOnePart target) 
      { 
       target.Cascade.All(); 
      } 

      public bool Accept(IOneToManyPart target) 
      { 
       return true; 
      } 

      public void Apply(IOneToManyPart target) 
      { 
       target.Cascade.All(); 
      } 

      public bool Accept(IManyToOnePart target) 
      { 
       return true; 
      } 

      public void Apply(IManyToOnePart target) 
      { 
       target.Cascade.All(); 
      } 
     } 

    } 

risposta

18

Il modo più semplice che ho trovato per fare questo per un intero progetto è quello di utilizzare DefaultCascade:

.Conventions.Add(DefaultCascade.All());  

Vai alla sezione "The Simplest Conventions" sul wiki, per questo, e un elenco di altri.

Edit: Ecco l'elenco dal Wiki:

Table.Is(x => x.EntityType.Name + "Table") 
PrimaryKey.Name.Is(x => "ID") 
AutoImport.Never() 
DefaultAccess.Field() 
DefaultCascade.All() 
DefaultLazy.Always() 
DynamicInsert.AlwaysTrue() 
DynamicUpdate.AlwaysTrue() 
OptimisticLock.Is(x => x.Dirty()) 
Cache.Is(x => x.AsReadOnly()) 
ForeignKey.EndsWith("ID") 

Una parola di avvertimento - alcuni dei nomi dei metodi della Wiki può essere sbagliato. Ho modificato il Wiki con quello che potevo verificare (ad esempio DefaultCascade e DefaultLazy), ma non posso garantire per il resto. Ma dovresti essere in grado di capire i nomi propri con Intellisense, se necessario.

+0

Grazie Tom. Questa è una soluzione davvero facile. Decisamente meno codice del mio modo :-) – Glenn

+1

Sono contento che ti piaccia - Di sicuro l'ho fatto quando mi sono stati segnalati sulla mailing list! Ho appena fatto una modifica importante sulla sezione Wiki http://wiki.fluentnhibernate.org/Conventions per attirare l'attenzione di più persone che usano FNH. –

1

La firma per le convenzioni è cambiato. Non stai usando qualcosa come ReSharper? Questo ti indicherebbe a questa conclusione.

Ulteriori informazioni sul nuovo conventions on the wiki.

+0

James, Grazie per il tuo eccellente lavoro su Fluent Nhibernate. Ho circa un giorno per implementarlo in un nuovo progetto e amo i tuoi esempi. Il codice (risposta sotto) viene eseguito senza errori e inserisce i valori previsti nel db. Il mio approccio ha senso? – Glenn

2

Ecco un esempio di lavoro completo simile alla Guida introduttiva https://github.com/jagregory/fluent-nhibernate/wiki/Getting-started

//=====CONSOLE MAIN 
    using System; 
    using System.Collections.Generic; 
    using System.Linq; 
    using System.Text; 

    using FluentNHibernate.Cfg; 
    using FluentNHibernate.Cfg.Db; 
    using NHibernate; 
    using NHibernate.Cfg; 
    using NHibernate.Tool.hbm2ddl; 
    using System.IO; 
    using FluentNHibernate.Automapping; 
    using App4.Entities; 
    using System.Diagnostics; 

    namespace App4 
    { 
     class Program 
     { 
      static void Main(string[] args) 
      { 
       // create our NHibernate session factory 
       var sessionFactory = CreateSessionFactory(); 

       using (var session = sessionFactory.OpenSession()) 
       { 
        // populate the database 
        using (var transaction = session.BeginTransaction()) 
        { 
         // create a couple of Stores each with some Products and Employees 
         var topShelf = new Shelf(); 
         var sw = new Stopwatch(); 
         sw.Start(); 
         for (var i = 0; i < 1000; i++) 
         { 
          var potatoes = new Product { Name = "Potatoes" + i.ToString(), Price = 3.60 + i }; 
          var meat = new Product { Name = "Meat" + i.ToString(), Price = 4.49 + i }; 
          //session.SaveOrUpdate(potatoes); //===<<cascading save handles this :-) 
          //session.SaveOrUpdate(meat); 
          topShelf.Products.Add(meat); 
          topShelf.Products.Add(potatoes); 
         } 
         sw.Stop(); 

         session.SaveOrUpdate(topShelf); 
         //session.SaveOrUpdate(superMart); 
         transaction.Commit(); 

         Console.WriteLine("Add Items: " + sw.ElapsedMilliseconds); 
        } 
       } 

       using (var session = sessionFactory.OpenSession()) 
       { 
        // retreive all stores and display them 
        using (session.BeginTransaction()) 
        { 
         var shelves = session.CreateCriteria(typeof(Shelf)).List<Shelf>(); 

         foreach (var store in shelves) 
         { 
          WriteShelfPretty(store); 
         } 
        } 
       } 

       Console.ReadLine(); 
      } 

      private const string DbFile = "FIVEProgram.db"; 
      private static ISessionFactory CreateSessionFactory() 
      { 
       return Fluently.Configure() 
        .Database(SQLiteConfiguration.Standard.UsingFile(DbFile)) 
        .Mappings(m => m.AutoMappings 
         .Add(AutoMap.AssemblyOf<Shelf>(type => type.Namespace.EndsWith("Entities")) 
           .Override<Shelf>(map => 
           { 
            map.HasManyToMany(x => x.Products);//.Cascade.All(); 
           }) 
           .Conventions.AddFromAssemblyOf<CascadeAll>() 
          ) 

        ) //emd mappings 
       .ExposeConfiguration(BuildSchema)//Delete and remake db (see function below) 
       .BuildSessionFactory();//finalizes the whole thing to send back. 

      } 

      private static void BuildSchema(Configuration config) 
      { 
       // delete the existing db on each run 
       if (File.Exists(DbFile)) 
        File.Delete(DbFile); 

       // this NHibernate tool takes a configuration (with mapping info in) 
       // and exports a database schema from it 
       new SchemaExport(config) 
        .Create(false, true); 
      } 

      private static void WriteShelfPretty(Shelf shelf) 
      { 
       Console.WriteLine(shelf.Id); 
       Console.WriteLine(" Products:"); 

       foreach (var product in shelf.Products) 
       { 
        Console.WriteLine(" " + product.Name); 
       } 

       Console.WriteLine(); 
      } 

     } 



    } 


//Data Classes 
using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 

namespace App4.Entities 
{ 
    public class Product 
    { 
     public virtual int Id { get; private set; } 
     public virtual string Name { get; set; } 
     public virtual double Price { get; set; } 
    } 

    public class Shelf 
    { 
     public virtual int Id { get; private set; } 
     public virtual IList<Product> Products { get; private set; } 

     public Shelf() 
     { 
      Products = new List<Product>(); 
     } 
    } 
} 



//Cascade All Helper Class 
using FluentNHibernate.Conventions; 
using FluentNHibernate.Conventions.AcceptanceCriteria; 
using FluentNHibernate.Conventions.Inspections; 
using FluentNHibernate.Conventions.Instances; 
using System; 
using System.Collections.Generic; 


namespace App4 
{ 
    public class CascadeAll : 
     IHasOneConvention, //Actually Apply the convention 
     IHasManyConvention, 
     IReferenceConvention, 
     IHasManyToManyConvention, 

     IHasOneConventionAcceptance, //Test to see if we should use the convention 
     IHasManyConventionAcceptance, //I think we could skip these since it will always be true 
     IReferenceConventionAcceptance, //adding them for reference later 
     IHasManyToManyConventionAcceptance 
    { 

     //One to One 

     public void Accept(IAcceptanceCriteria<IOneToOneInspector> criteria) 
     { 
      //criteria.Expect(x => (true)); 
     } 

     public void Apply(IOneToOneInstance instance) 
     { 
      instance.Cascade.All(); 
     } 




     //One to Many 

     public void Accept(IAcceptanceCriteria<IOneToManyCollectionInspector> criteria) 
     { 
      //criteria.Expect(x => (true)); 
     } 

     public void Apply(IOneToManyCollectionInstance instance) 
     { 
      instance.Cascade.All(); 
     } 




     //Many to One 

     public void Accept(IAcceptanceCriteria<IManyToOneInspector> criteria) 
     { 
      // criteria.Expect(x => (true)); 
     } 

     public void Apply(IManyToOneInstance instance) 
     { 
      instance.Cascade.All(); 
     } 





     //Many to Many 

     public void Accept(IAcceptanceCriteria<IManyToManyCollectionInspector> criteria) 
     { 
      // criteria.Expect(x => (true)); 
     } 

     public void Apply(IManyToManyCollectionInstance instance) 
     { 
      instance.Cascade.All(); 
     } 



    } 


} 
+1

Sembra buono!Le interfacce Acceptance non devono essere implementate se non si stanno utilizzando i criteri, ma ritengo che sappiate già che si basano sui vostri commenti. –

+0

È bello avere la flessibilità di questo metodo e la semplicità del metodo che Tom menziona di seguito per il caso normale. Non vedo l'ora che sia facile la manutenzione di Fluent. Anche la velocità è ottima, ottengo migliaia di inserti al secondo utilizzando il disco associato a slq lite con questo codice di test in modalità di debug. – Glenn

Problemi correlati