2011-02-10 14 views
0

すべてのメモリを取得する場所を試してみるために、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)); 
    } 
} 

答えて

2

問題は、データと操作を表現するために同じクラスを使用していることです。そうすることで、ドメインモデルと永続性が結合されます。

私が正しく理解している場合、User.Configは、単一のフィールドにXMLとしてシリアル化する文字列の一覧に過ぎません。あなたはその後(私はXMLStringListTypeそれを呼びたい)

List<string>(またはIList<string>)としてプロパティを作成し、XMLにそれをシリアル化することができIUserTypeを作成する必要があります

、あなたはちょうどあなたのような流暢にそれをマッピングすることができますされている。

+1

Diegoと同意します。 IUserTypeの名前が不適切なインターフェイスかもしれません。これは、データベースフィールドとあなたのpocoの間の変換パイプラインです。あなたのPOCOがきれいに保たれることを望むので、これは理にかなっています。この場合、POCOはNHibernate自体に依存しています。良いことではありません。 – Rich

+1

@Richは良い点があります。私は最初にIType/IUserTypeが混乱しているのを見つけました(これはJavaから来ていることを忘れないでください、BTW)。 IUserTypeMapperはより良い名前でした。 –

関連する問題