2011-04-29 93 views
1

我有这样的代码:NHibernate的二级缓存不缓存整个实体

[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; } 
} 

这会产生这样的输出:

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 

我第二次使用的顺序取Get方法,它不查询Order表,但它仍然对OrderRow表进行查询。

这可以通过某种方式进行配置,以便将它与订单表数据一起缓存?

+0

并设置取的集合映射做=“加盟”? – Vadim 2011-04-29 15:06:12

回答

2

集合高速缓存与实体高速缓存分开处理。假设他们越来越automapped为.HasMany,您可以定义一个约定此像这样:

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

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