NHibernate SysCache 不缓存 children objects
NHibernate SysCache does not cache children objects
希望得到您的帮助。
我有简单的 master-child 集("player" 和 "playerChildObject")。获取 "players" 也会获取其链接的 children.
SysCache 缓存玩家,但不缓存 children.
这里是 objects(都用 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; }
}
映射:
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();
}
}
会话工厂也有 "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(true).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();
}
}
但是,探查器显示玩家已缓存(仅在第一次执行玩家获取代码时调用),而每次 PlayerID 都会检索相同的 PlayerChildObjects。
因此,第一个请求给出 N+1 个 DB 调用(玩家列表 + child objects 每个玩家),所有连续的请求执行 N 个调用(child objects 每个玩家)。
我错过了什么? 如何让SysCache缓存也children?
系统缓存版本:3.1.0.4000
我想说,有两个问题。首先,即使 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(Adam Bar 的文章关于按代码映射,但最后是流利的)
其次,我们应该使用批量获取:
public PlayerMap()
{
BatchSize(25);
HasMany(x => x.PlayerChildObjects).KeyColumn("PlayerId")
...
.BatchSize(25)
...
public PlayerChildObjectMap()
{
BatchSize(25);
...
在文档 19.1.5. Using batch fetching 或此处阅读更多相关信息:
- How to Eager Load Associations without duplication in NHibernate?
- How to implement batch fetching with Fluent NHibernate when working with Oracle?
希望得到您的帮助。 我有简单的 master-child 集("player" 和 "playerChildObject")。获取 "players" 也会获取其链接的 children.
SysCache 缓存玩家,但不缓存 children.
这里是 objects(都用 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; }
}
映射:
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();
}
}
会话工厂也有 "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(true).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();
}
}
但是,探查器显示玩家已缓存(仅在第一次执行玩家获取代码时调用),而每次 PlayerID 都会检索相同的 PlayerChildObjects。
因此,第一个请求给出 N+1 个 DB 调用(玩家列表 + child objects 每个玩家),所有连续的请求执行 N 个调用(child objects 每个玩家)。
我错过了什么? 如何让SysCache缓存也children?
系统缓存版本:3.1.0.4000
我想说,有两个问题。首先,即使 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(Adam Bar 的文章关于按代码映射,但最后是流利的)
其次,我们应该使用批量获取:
public PlayerMap()
{
BatchSize(25);
HasMany(x => x.PlayerChildObjects).KeyColumn("PlayerId")
...
.BatchSize(25)
...
public PlayerChildObjectMap()
{
BatchSize(25);
...
在文档 19.1.5. Using batch fetching 或此处阅读更多相关信息:
- How to Eager Load Associations without duplication in NHibernate?
- How to implement batch fetching with Fluent NHibernate when working with Oracle?