【问题标题】:NHibernate 2nd level cache don't cache the whole entityNHibernate 2 级缓存不缓存整个实体
【发布时间】:2011-08-15 10:55:21
【问题描述】:

我有这个代码:

[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 order0_.Id=@p0;@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 rows0_.OrderId=@p0;@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 rows0_.OrderId=@p0;@p0 = 1 [Type: Int32 (0)]
2

我第二次使用 Get 方法获取 Order 时,它不会查询 Order 表,但它仍然会查询 OrderRow 表。

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

【问题讨论】:

  • 在集合映射上设置 fetch="join" 可以吗?

标签: c# .net nhibernate fluent-nhibernate second-level-cache


【解决方案1】:

集合缓存与实体缓存分开处理。假设它们被自动映射为 .HasMany,您可以像这样定义一个约定:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-02
    • 1970-01-01
    • 1970-01-01
    • 2017-08-17
    • 2016-04-27
    • 2010-11-26
    相关资源
    最近更新 更多