2010-02-11 7 views
8

chcę zrobić dokładnie to, co to pytanie pyta: Cascade Saves with Fluent NHibernate AutoMappingKaskada zapisuje z Fluent NHibernate AutoMapping - Stara odpowiedź jest nadal ważna?

Korzystanie Fluent NHibernate mapowania, aby włączyć „kaskady” globalnie raz dla wszystkich klas i typów relacji z zastosowaniem raczej jedno połączenie niż ustawienie go indywidualnie dla każdego odwzorowania.

Odpowiedź na wcześniejsze pytanie wygląda świetnie, ale obawiam się, że interfejs Fluent Nhibernate API zmienił jego składnię .WithConvention w zeszłym roku i złamał odpowiedź ... albo czegoś brakuje.

Dostaję sporo przestrzeni nazw nie wykrył błędy dotyczące IOneToOnePart, IManyToOnePart i wszystkie ich odmiany:

„typu lub obszaru nazwa«IOneToOnePart»nie można odnaleźć (czy brakuje using dyrektywa lub odniesienie do zespołu?) "

Próbowałem oficjalnych dll przykład, dll RTM i najnowszej kompilacji i żaden z nich nie wydaje się, aby VS 2008 zobaczyć wymaganą przestrzeń nazw.

Drugim problemem jest to, że chcę użyć klasy z moim AutoPersistenceModel ale nie jestem pewien, gdzie do tej linii: .ConventionDiscovery.AddFromAssemblyOf() w moim sposobie tworzenia fabryki.

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. 

      } 

Poniżej jest klasa i obsługa oświadczenia Próbuję

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

    } 

Odpowiedz

18

Najprostszym sposobem znalazłem to zrobić dla całego projektu jest wykorzystanie DefaultCascade:

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

Przejdź do sekcji "The Simplest Conventions" na wiki, do tego i listy innych.

Edit: Oto lista z encyklopedii:

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

Słowo ostrzeżenia - niektóre nazwy metody w Wiki może być źle. Edytowałem Wiki z tym, co mogłem zweryfikować (np. DefaultCascade i DefaultLazy), ale nie mogę ręczyć za resztę. Ale jeśli zajdzie taka potrzeba, powinieneś być w stanie wymyślić odpowiednie nazwy za pomocą IntelliSense.

+0

Dzięki Tom. To naprawdę proste rozwiązanie. Zdecydowanie mniej kodu niż na swój sposób :-) – Glenn

+1

Cieszę się, że Ci się podoba - na pewno zrobiłem, kiedy zostali mi wskazani na liście mailingowej! Właśnie dokonałem ważnej edycji w sekcji Wiki http://wiki.fluentnhibernate.org/Conventions, aby zwrócić na to uwagę większej liczby osób korzystających z FNH. –

1

podpis na konwencji nie zmieniło. Czy nie używasz czegoś takiego jak ReSharper? To wskazywałoby na taki wniosek.

Możesz przeczytać więcej o nowym conventions on the wiki.

+0

James, Dziękuję za wspaniałą pracę nad Fluent Nhibernate. Mam około jednego dnia na wdrożenie go w nowym projekcie i kocham twoje przykłady. Kod (odpowiedź poniżej) działa bez błędów i umieszcza oczekiwane wartości w db. Czy moje podejście ma sens? – Glenn

2

Oto pełna przykładów praca podobna do Getting Started Guide 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

Wygląda dobrze!Interfejsy akceptacji nie muszą być implementowane, jeśli nie używasz tych kryteriów, ale rozumiem, że już wiesz na podstawie twoich komentarzy. –

+0

Fajnie jest mieć elastyczność tej metody i prostotę metody, o której Tom wspomniał poniżej w normalnym przypadku. Naprawdę nie mogę się doczekać łatwej konserwacji, którą przyniesie Fluent. Prędkość też jest świetna, dostaję tysiące insertów na sekundę przy użyciu dysku slq lite związanego z dyskiem z tym kodem testowym w trybie debugowania. – Glenn

Powiązane problemy