2015-04-16 4 views
2

Надеюсь на вашу помощь. У меня есть простые наборы мастера-ребенка («игрок» и «playerChildObject»). Извлечение «игроков» также позволяет связанным детям.NHibernate SysCache не кэширует дочерние объекты

SysCache кэширует игроков, однако не кэширует детей.

Вот объекты (как набор с Cache.ReadWrite()):

Сущности:

public class Player 
{ 
    public virtual int Id { get; set; } 
    public virtual string Name { get; set; } 
    public virtual IList<PlayerChildObject> PlayerChildObjects { get; set; } 

    public Player() 
    { 
     PlayerChildObjects = new List<PlayerChildObject>(); 
    } 
} 

public class PlayerChildObject 
{ 
    public virtual int Id { get; protected set; } 
    public virtual Player Player { get; set; } 
} 

Mapping:

public class PlayerMap : ClassMap<Player> 
{ 
    public PlayerMap() 
    { 
     Id(x => x.Id).Column("id"); 
     Map(x => x.Name).Column("name"); 
     HasMany(x => x.PlayerChildObjects).KeyColumn("PlayerId") 
      .Inverse() 
      .Cascade.All() 
      .Not.LazyLoad(); 
     Table("accounts"); 
     Cache.ReadWrite(); 
    } 
} 

public class PlayerChildObjectMap : ClassMap<PlayerChildObject> 
{ 
    public PlayerChildObjectMap() 
    { 
     Id(x => x.Id).Column("id"); 
     References<Player>(x => x.Player, "playerId"); 
     Table("playerChildObjects"); 
     Cache.ReadWrite(); 
    } 
} 

Session завод также с "UseQueryCache" и «UseSecondLevelCache»:

Fluently.Configure() 
.Database(MySQLConfiguration.Standard.ConnectionString(cs => ...)) 
.Cache(c => c.UseQueryCache().UseSecondLevelCache() 
.ProviderClass(typeof (NHibernate.Caches.SysCache.SysCacheProvider).AssemblyQualifiedName)) 
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<PlayerChildObjectMap>()) 
.BuildSessionFactory(); 

И сам запрос с SetCacheable (истина) .SetCacheMode (CacheMode.Normal):

using (var session = SessionFactory.OpenSession()) 
{ 
    using (var transaction = session.BeginTransaction()) 
    { 
     players = session.CreateCriteria(typeof(Player)) 
      .SetCacheable(true) 
      .SetCacheMode(CacheMode.Normal) 
      .List<Player>(); 
     transaction.Commit(); 
    } 
} 

Однако профайлер показывает, что игроки кэшируются (называется только первый раз игроки выполнения выборки коды), в то время как тот же PlayerChildObjects каждый раз извлекаются с помощью PlayerID.

Итак, первый запрос дает N + 1 DB-вызовы (список игроков + дочерние объекты каждым игроком), все последовательные запросы выполняют N вызовов (дочерние объекты по каждому игроку).

Что мне не хватает? Как сделать кеширование SysCache детьми?

версия SysCache: 3.1.0.4000

ответ

2

Я бы сказал, есть два вопроса. Во-первых, даже one-to-many(HasMany) имеет настройки кэша:

HasMany(x => x.PlayerChildObjects).KeyColumn("PlayerId") 
    ... 
    .Cache.IncludeAll() // or .IncludeNonLazy, .CustomInclude("customInclude") 
     .ReadOnly() // or .NonStrictReadWrite(), .ReadWrite(), .Transactional(), 
        // .CustomUsage("customUsage")   
     .Region("regionName"); 

Проверить более примыкают HasMany mapping here (статья Адама Бара об отображении кода, но в конце концов, это свободно один)

док 19.2.1. Cache mappings

Во-вторых, мы должны использовать пакетную выборку:

public PlayerMap() 
{ 
    BatchSize(25); 

    HasMany(x => x.PlayerChildObjects).KeyColumn("PlayerId") 
     ... 
     .BatchSize(25) 
... 
public PlayerChildObjectMap() 
{ 
    BatchSize(25); 
    ... 

Подробнее об этом в документ 19.1.5. Using batch fetching или здесь:

+0

Я надеюсь, что эта магия работает. Собираюсь проверить его сегодня вечером. –

+0

Он делает! До сих пор я пропускал партии, так как ожидал не более 10 детей для каждого игрока. Но эта строка сделала это: 'HasMany (x => ......). Cache.IncludeAll(). ReadWrite();' Danke! –

+0

Замечательно видеть, что сэр! ;) Наслаждайтесь могучим NHiberante;) –

Смежные вопросы