2011-04-29 2 views
1

J'ai ce code:NHibernate cache de niveau 2 ne cache pas toute entité

[TestFixture] 
public class CachingTest 
{ 
    [Test] 
    public void Caches_second_request() 
    { 
     var sessionFactory = CreateSessionFactory(); 

     int orderId; 
     { 
      var order = new Order {Created = DateTime.Now}; 
      order.Rows.Add(new OrderRow {Price = 123, Order = order}); 
      order.Rows.Add(new OrderRow { Price = 456, Order = order }); 

      using (var session = sessionFactory.OpenSession()) 
      { 
       session.Save(order); 
       orderId = order.Id; 
      } 
     } 

     Console.WriteLine("Saved"); 

     using (var session = sessionFactory.OpenSession()) 
     { 
      var order = session.Get<Order>(orderId); 

      Console.WriteLine(order.Rows.Count); 
     } 

     Console.WriteLine("Fetched first time"); 

     using (var session = sessionFactory.OpenSession()) 
     { 
      var order = session.Get<Order>(orderId); 

      Console.WriteLine(order.Rows.Count); 
     } 
    } 

    private static ISessionFactory CreateSessionFactory() 
    { 
     var autoMappingConfig = new AutoMappingConfiguration(); 

     ISessionFactory sessionFactory = Fluently.Configure() 
      .Database(MsSqlConfiguration.MsSql2008 
          .ConnectionString(c => c.FromAppSetting("connectionString")) 
          .ShowSql()) 
      .Cache(c => c 
          .UseQueryCache() 
          .UseSecondLevelCache() 
          .ProviderClass<KamakuraCacheProvider>()) 
      .Mappings(m => 
         m.AutoMappings.Add(
          AutoMap.AssemblyOf<CachingTest>(autoMappingConfig) 
           .Conventions.Add(
            ForeignKey.EndsWith("Id"), 
            DefaultLazy.Never(), 
            DefaultCascade.All()) 
           .Conventions.Add<CacheableConvention>() 
         )) 
      .ExposeConfiguration(configuration => 
           new SchemaExport(configuration).Create(false, true)) 
      .BuildSessionFactory(); 

     return sessionFactory; 
    } 
} 

public class CacheableConvention : IClassConventionAcceptance, IClassConvention 
{ 
    public void Accept(IAcceptanceCriteria<IClassInspector> criteria) 
    { 
     criteria.Expect(x => x.EntityType.IsAny(typeof (Order), typeof (OrderRow))); 
    } 

    public void Apply(IClassInstance instance) 
    { 
     instance.Cache.ReadWrite(); 
     instance.Cache.IncludeAll(); 
    } 
} 

public class AutoMappingConfiguration : DefaultAutomappingConfiguration 
{ 
    public override bool ShouldMap(Type type) 
    { 
     return type == typeof (Order) || type == typeof (OrderRow); 
    } 

    public override Access GetAccessStrategyForReadOnlyProperty(Member member) 
    { 
     return Access.ReadOnlyPropertyThroughCamelCaseField(CamelCasePrefix.Underscore); 
    } 
} 

public class Order 
{ 
    private readonly ICollection<OrderRow> _rows = new Collection<OrderRow>(); 

    public virtual int Id { get; set; } 

    public virtual DateTime Created { get; set; } 

    public virtual ICollection<OrderRow> Rows 
    { 
     get { return _rows; } 
    } 
} 

public class OrderRow 
{ 
    public virtual int Id { get; set; } 

    public virtual Order Order { get; set; } 

    public virtual decimal Price { get; set; } 
} 

Cela va générer cette sortie:

NHibernate: INSERT INTO [Order] (Created) VALUES (@p0); select SCOPE_IDENTITY();@p0 = 2011-04-29 13:40:39 [Type: DateTime (0)] 
NHibernate: INSERT INTO [OrderRow] (Price, OrderId) VALUES (@p0, @p1); select SCOPE_IDENTITY();@p0 = 123 [Type: Decimal (0)], @p1 = 1 [Type: Int32 (0)] 
NHibernate: INSERT INTO [OrderRow] (Price, OrderId) VALUES (@p0, @p1); select SCOPE_IDENTITY();@p0 = 456 [Type: Decimal (0)], @p1 = 1 [Type: Int32 (0)] 
Saved 
NHibernate: SELECT order0_.Id as Id0_0_, order0_.Created as Created0_0_ FROM [Order] order0_ WHERE [email protected];@p0 = 1 [Type: Int32 (0)] 
NHibernate: SELECT rows0_.OrderId as OrderId1_, rows0_.Id as Id1_, rows0_.Id as Id1_0_, rows0_.Price as Price1_0_, rows0_.OrderId as OrderId1_0_ FROM [OrderRow] rows0_ WHERE [email protected];@p0 = 1 [Type: Int32 (0)] 
2 
Fetched first time 
NHibernate: SELECT rows0_.OrderId as OrderId1_, rows0_.Id as Id1_, rows0_.Id as Id1_0_, rows0_.Price as Price1_0_, rows0_.OrderId as OrderId1_0_ FROM [OrderRow] rows0_ WHERE [email protected];@p0 = 1 [Type: Int32 (0)] 
2 

La deuxième fois que je l'Ordre à l'aide aille chercher la Get méthode, il n'interroge pas la table Order, mais il fait toujours la requête à la table OrderRow.

Est-ce que cela peut être configuré d'une certaine manière pour qu'il soit mis en cache avec les données de la table de commande?

+0

ne réglage fetch = « join » sur le mapping de la collection faire? – Vadim

Répondre

2

La mise en cache de la collection est traitée séparément de la mise en cache des entités. En supposant qu'ils obtiennent automapped comme .HasMany, vous pouvez définir une convention pour cela comme si:

public class CacheableCollectionConvention : IHasManyConvention, IHasManyConventionAcceptance { 
    public void Apply (IOneToManyCollectionInstance instance) { 
     instance.Cache.ReadWrite(); 
    } 

    public void Accept (IAcceptanceCriteria<IOneToManyCollectionInspector> criteria) { 
     //whatever 
    } 
} 
Questions connexes