すべてのメモリを取得する場所を試してみるために、NHibernateを少しのメモリ空腹の獣 - しかし、私は本当に1つの最後までだ:NHibernateのIUserTypeを理解し、それがメモリ内に残っている理由
カスタム・タイプは、メモリに保持されているように見える、メモリのビットは以下のコードを実行した後
**を漏らす引き起こして、I記憶をプロファイリングする。 UserConfigのインスタンスが残っていた(UserインスタンスはGCされていました) - ユーザーが行ったように、私はUserConfigのインスタンスもなくなると予想していました。 「インスタンス保持グラフ」には、次の情報が表示されます。
UserConfig | NHibernate.Type.CustomType | NHibernate.Type.IType [] | NHbernate.Persister.Entity.SingleTableEntityPersister | System.Collections ..... | System.Collections ..... | NHibernate.Impl.SessionFactoryImpl | SessionSource
私はここにいくつかのコードを示しました(コード自体にコメントしないでください - この問題をテストするためにこのコードを書いています。実用的なコードではありません)。
メモリスナップショット内のすべてが問題の一部になるように、モジュールの最後にGC.Collect()を追加しました。私はコードの関連部分のみを含めました
(あなたがプロジェクト全体をたい場合は、私にメールしてください)
CustomTypeを使用していないことはオプションではありません。
セッションファクトリ...
SessionFactory = Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2008.ConnectionString(ConfigurationManager.ConnectionStrings["ConnectionString"].ToString()))
.Mappings(x => GetFluantMappings(x))
.ExposeConfiguration(c =>
{
c.SetProperty("generate_statistics", "true");
c.SetProperty("current_session_context_class", contextClass);
c.SetProperty("cache.use_second_level_cache", "false");
c.SetProperty("cache.use_query_cache", "false");
})
.BuildSessionFactory();
}
catch(FluentConfigurationException ex)
{
throw new SessionSourceException("Error initializing session factory", ex);
}
要求HttpModuleをセッションごと
private static void BeginRequest(object sender, EventArgs e)
{
ISession session = SessionSource.Instance.SessionFactory.OpenSession();
ManagedWebSessionContext.Bind(HttpContext.Current, session);
}
private static void EndRequest(object sender, EventArgs e)
{
ISession session = ManagedWebSessionContext.Unbind(HttpContext.Current, SessionSource.Instance.SessionFactory);
if (session == null) return;
session.Close();
session.Dispose();
GC.Collect();
}
ASPXページ
protected void Page_Load(object sender, EventArgs e)
{
int userId = CreateUser(SessionSource.Instance.SessionFactory);
GetUser(SessionSource.Instance.SessionFactory, userId);
}
private static void GetUser(ISessionFactory sessionFactory, int userId)
{
ISession session = sessionFactory.GetCurrentSession();
User user = session.Get<User>(userId);
//User user = session.Query<User>().Single(u => u.Id == userId);
}
private static int CreateUser(ISessionFactory sessionFactory)
{
User user = new User();
user.Created = DateTime.Now;
user.Email = "[email protected]";
user.Enabled = true;
user.FirstName = "first name";
user.LastName = "last name";
user.Password = "password";
user.ScreenName = "firstname lastname";
ISession session = sessionFactory.GetCurrentSession();
session.SaveOrUpdate(user);
return user.Id;
}
Userクラスとユーザーマップ
public class User
{
public virtual int Id { get; set; }
public virtual string Email { get; set; }
public virtual string ScreenName { get; set; }
public virtual string Password { get; set; }
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual bool Enabled { get; set; }
public virtual DateTime Created { get; set; }
public virtual DateTime? LastLogin { get; set; }
public virtual DateTime? LastActivity { get; set; }
public virtual UserConfig Config { get; set; }
}
[Serializable]
public class UserConfig : List<string>, IUserType
{
public UserConfig() { }
public UserConfig(IEnumerable<string> items) : base(items)
{
}
#region IUserType Members
public object Assemble(object cached, object owner)
{
return DeepCopy(cached);
}
public object DeepCopy(object value)
{
return value;
}
public object Disassemble(object value)
{
return DeepCopy(value);
}
public new bool Equals(object x, object y)
{
if (ReferenceEquals(x, y)) return true;
if (x == null || y == null) return false;
return x.Equals(y);
}
public int GetHashCode(object x)
{
return x.GetHashCode();
}
public bool IsMutable
{
get { return false; }
}
public object NullSafeGet(IDataReader rs, string[] names, object owner)
{
object obj = NHibernateUtil.String.NullSafeGet(rs, names[0]);
if (obj == null)
{
return new UserConfig();
}
return XmlSerialiser.FromXml<UserConfig>(obj as string);
}
public void NullSafeSet(IDbCommand cmd, object value, int index)
{
var parameter = (IDataParameter)cmd.Parameters[index];
if (value == null)
{
parameter.Value = DBNull.Value;
}
else
{
parameter.Value = XmlSerialiser.ToXml<UserConfig>(value);
}
}
public object Replace(object original, object target, object owner)
{
return original;
}
[XmlIgnore]
public Type ReturnedType
{
//the .Net type that this maps to
get { return typeof(UserConfig); }
}
[XmlIgnore]
public SqlType[] SqlTypes
{
//the sql type that this maps to
get { return new[] { SqlTypeFactory.GetString(int.MaxValue), }; }
}
#endregion
}
public class XmlSerialiser
{
public static XmlSerializerNamespaces GetNamespaces()
{
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add(string.Empty, string.Empty);
return ns;
}
//Creates an object from an XML string.
public static T FromXml<T>(string xml) where T : new()
{
return FromXml<T>(xml,() => new T());
}
public static T FromXml<T>(string xml, Func<T> func)
{
if (xml == "<nil-classes type=\"array\" />")
{
return func();
}
XmlSerializer ser = new XmlSerializer(typeof(T));
StringReader stringReader = new StringReader(xml);
XmlTextReader xmlReader = new XmlTextReader(stringReader);
try
{
object obj = ser.Deserialize(xmlReader);
xmlReader.Close();
stringReader.Close();
return (T) obj;
}
finally
{
stringReader.Dispose();
}
}
public static string ToXml(Type type, object obj)
{
XmlSerializer ser = new XmlSerializer(type);
MemoryStream memStream = new MemoryStream();
XmlTextWriter xmlWriter = new XmlTextWriter(memStream, Encoding.Unicode);
try
{
xmlWriter.Namespaces = true;
ser.Serialize(xmlWriter, obj, GetNamespaces());
xmlWriter.Close();
memStream.Close();
string xml = Encoding.Unicode.GetString(memStream.GetBuffer());
xml = xml.Substring(xml.IndexOf(Convert.ToChar(60)));
xml = xml.Substring(0, (xml.LastIndexOf(Convert.ToChar(62)) + 1));
return xml;
}
finally
{
memStream.Dispose();
}
}
//Serializes the <i>Obj</i> to an XML string.
public static string ToXml<T>(object obj)
{
return ToXml(typeof(T), obj);
}
}
public sealed class UserMap : ClassMap<User>
{
public UserMap()
{
Id(x => x.Id).Column("UserId");
Map(x => x.Created);
Map(x => x.Email);
Map(x => x.Enabled);
Map(x => x.FirstName);
Map(x => x.LastActivity);
Map(x => x.LastLogin);
Map(x => x.LastName);
Map(x => x.Password);
Map(x => x.ScreenName);
Map(x => x.Config).CustomType(typeof(UserConfig));
}
}
Diegoと同意します。 IUserTypeの名前が不適切なインターフェイスかもしれません。これは、データベースフィールドとあなたのpocoの間の変換パイプラインです。あなたのPOCOがきれいに保たれることを望むので、これは理にかなっています。この場合、POCOはNHibernate自体に依存しています。良いことではありません。 – Rich
@Richは良い点があります。私は最初にIType/IUserTypeが混乱しているのを見つけました(これはJavaから来ていることを忘れないでください、BTW)。 IUserTypeMapperはより良い名前でした。 –