2009-10-26 17 views
15

NHibernate'i F # 'nin ayrımcı birliğini desteklemek için genişletmenin nispeten kolay bir yolu olup olmadığını merak ediyorum. Sadece tek bir IUserType veya ICompositeUserType değil, DU'nın asıl içeriği ne olursa olsun yeniden kullanabileceğim genel bir şey.NHibernate'deki ayrımcılık yapılan sendikalar

type RequestInfo = 
    | Id of int 
    | Name of string 

Bu derler soyut RequestInfo sınıfa, beton alt sınıfları Id ve Adı:

Örneğin, ben olarak tanımlanan bir birliktir RequestInfo adlı bir özellik olduğunu varsayın. Tüm bu bilgiyi F # yansımasıyla gayet iyi anlayabiliyorum. Bu durumda veritabanında "RequestInfo_Tag", "RequestInfo_Id", "RequestInfo_Name" ile saklayabilirim.

Ben bir NHibernate acemi olduğum için, bu yaklaşımı takip etmeye çalışmak için ne tür sorunlarla karşılaşacağım? Daha karmaşık vakalarla uğraşmak imkansız mı olacak? Örneğin, iç içe geçmiş ayrımcılı sendikalar? Birliğin geri kalan kısmının okunmasını başka bir ICompositeUserType'a "devredebileceğim" bir yol var mı?

Daha da önemlisi, bu, sorgulama yeteneklerimi bozacak mı? Anlamı, DB'deki gerçek sütun isimlerini bilmem gerekecek; Criteria.Eq (SomeDiscUnion) yapamayacağım ve hepsini halledemeyeceğim?

Tam bir "kod sağla" cevabını aramıyorum, eğer bu bile devam edip etmeyeceğine dair genel bir tavsiyede (ve nasıl gösterileceğine dair bazı göstergeler) veya modelimi yeniden düşünmem gerekiyorsa.

Teşekkürler!

P.S. Kaba olmamak için, ama cevabınız "C# kullanın" dan oluşursa, bu çok yararlı değildir.

+1

Çok ilginç bir soru. Ben hem NHibernate hem de F # 'da oldukça akıcıyım, biraz zaman aldığımda bununla başa çıkacağım –

+0

En azından benim deneyimlerimde, NHibernate ile F # kullanarak çoğunlukla zor zamanlar geçirdim, çünkü çoğunlukla NHibernate varsayılan bir kurucuya sahip olmak için nesneler gerektirir sık sık sendika türleri, kayıt türleri ve çoğu sınıf için geçerli değildir) ve sınıflara değerler atamak için mutabiliteye dayanır (F # sınıfı tanımlarında sıkça karşılaşmak sıkıcıdır). Daha sık olmamakla birlikte, veritabanını kendi mirco-ORM'imi yuvarlayarak F # ile oynayacağım. – Juliet

+0

Evet, son projemizde sadece eski eski nesne tiplerine yapıştık, böylece NHibernate ile güzelce oynayacaklardı. Bu sefer biraz dalıp biraz daha gerçekçi modeller denemek istiyorum. – MichaelGG

cevap

7

NHibernate'i F # türü sistemiyle kullanmayı denemek için yeterince cesur olmadım, ancak F # derleyicisi tarafından gerçekten neyin oluşturulduğunun perspektifinden bakmaya yardımcı olabilir.

Yansıtılmış Birliğinize yansıtıcıya bakarsanız, aslında oluşturulan üç sınıf vardır (ve özel hata ayıklama proxy'lerini sayıyorsanız daha fazla).

public abstract class RequestInfo : IStructuralEquatable, IComparable, IStructuralComparable 

Birinci sınıf, RequestInfo, soyutdur ve aslında, birliğin diğer türleri tarafından uygulanır. bunu yaptığında

// Nested Types 
    [Serializable, DebuggerTypeProxy(typeof([email protected])), DebuggerDisplay("{__DebugDisplay()}")] 
    public class _Id : Program.RequestInfo 
    { 
     // Fields 
     [DebuggerBrowsable(DebuggerBrowsableState.Never), CompilerGenerated, DebuggerNonUserCode] 
     public readonly int id1; 

     // Methods 
     [CompilerGenerated, DebuggerNonUserCode] 
     public _Id(int id1); 
    } 
    [Serializable, DebuggerTypeProxy(typeof([email protected])), DebuggerDisplay("{__DebugDisplay()}")] 
    public class _Name : Program.RequestInfo 
    { 
     // Fields 
     [DebuggerBrowsable(DebuggerBrowsableState.Never), CompilerGenerated, DebuggerNonUserCode] 
     public readonly string name1; 

     // Methods 
     [CompilerGenerated, DebuggerNonUserCode] 
     public _Name(string name1); 
    } 

yüzden:

let r=Id(5) 
let s=Name("bob") 

r ve s sırasıyla _ID ve _name örnekleridir.

Yani sorunun cevabı aşağıdaki soruların birine muhtemel cevabı:

  • ben nhibernate içinde soyut bir sınıfa haritasına nasıl?
  • NHibernate'i bir fabrika yöntemini nasıl kullanabilirim?
  • Harita nasıl oluşturulur? Değişmez nesnelere Nhibernate?
  • NHibernate'de (muhtemelen IUserType ile) özel bir türü nasıl uygularım?

Maalesef, bunlardan herhangi birine tutarlı bir cevap vermek için yeterince bilgim yok, ama eminim ki buradaki bir başkası bu üç çözümden en az birini yaptı.

Örneğin, bir ayrımcı sütunu kullanarak Kalıtım Stratejileri için kullanılan yöntemlerin aynısını kullanabileceğinizi düşünmekteyim, ancak bir varsayılan kurucunun yokluğunun bu sorunu çözdüğünden korkuyorum. Bu yüzden özel bir tip kullanmanın çözüm olduğunu düşünmeye meyilliyim. Bazı işe yaramaz sonra

, burada (muhtemelen arabası ve ya kırık) özel kullanıcı tipi var:

type RequestInfo = 
    | Id of int 
    | Name of string 

type RequestInfoUserType() as self = 
    interface IUserType with 
     member x.IsMutable = false 
     member x.ReturnedType = typeof<RequestInfo> 
     member x.SqlTypes = [| NHibernate.SqlTypes.SqlType(Data.DbType.String); NHibernate.SqlTypes.SqlType(Data.DbType.Int32); NHibernate.SqlTypes.SqlType(Data.DbType.String) |] 
     member x.DeepCopy(obj) = obj //Immutable objects shouldn't need a deep copy 
     member x.Replace(original,target,owner) = target // this might be ok 
     member x.Assemble(cached, owner) = (x :> IUserType).DeepCopy(cached) 
     member x.Disassemble(value) = (x :> IUserType).DeepCopy(value) 

     member x.NullSafeGet(rs, names, owner)= 
      // we'll use a column as a type discriminator, and assume the first mapped column is an int, and the second is a string. 
      let t,id,name = rs.GetString(0),rs.GetInt32(1),rs.GetString(2) 
      match t with 
       | "I" -> Id(id) :> System.Object 
       | "N" -> Name(name) :> System.Object 
       | _ -> null 
     member x.NullSafeSet(cmd, value, index)= 
      match value with 
       | :? RequestInfo -> 
        let record = value :?> RequestInfo 
        match record with 
         | Id(i) -> 
          cmd.Parameters.Item(0) <- "I" 
          cmd.Parameters.Item(1) <- i 
         | Name(n) -> 
          cmd.Parameters.Item(0) <- "N" 
          cmd.Parameters.Item(2) <- n 
       | _ -> raise (new ArgumentException("Unexpected type")) 

     member x.GetHashCode(obj) = obj.GetHashCode() 
     member x.Equals(a,b) = 
      if (Object.ReferenceEquals(a,b)) then 
       true 
      else 
       if (a=null && b=null) then 
        false 
       else 
        a.Equals(b) 
    end 

Bu kod kesinlikle daha genel yapılmış olabilir ve muhtemelen gerçek etki alanı tabakasında olmamalı, ama ben IUserType bir F # uygulamasında bir bıçak almak yararlı olacağını düşündüm.

Kişisel eşleme dosyası daha sonra böyle bir şey yapsın:

<property name="IdOrName" type="MyNamespace.RequestInfoUserType, MyAssembly" > 
    <column name="Type"/> 
    <column name="Id"/> 
    <column name="Name"/> 
</property> 

Muhtemelen uzakta özel UserType kodunda küçük çimdik ile "Tür" için bir sütun olmadan alabilirsiniz.

Bu özel kullanıcı türlerinin, daha önce özel kullanıcı türleriyle gerçekten çalışmadığım için sorgularla/ICriteria ile nasıl çalıştığını bilmiyorum.

+0

Evet, tek bir eşleştirmeyi eşleme nispeten kolaydır. Fakat bir DU bir DU veya başka bir şey içeriyorsa ne olur? Sanırım tüm durumlarda doğru bir şekilde eşlemek için bu tür bir şey için özyineli bazı gelişmiş bileşik kullanıcı türüne ihtiyacım var. Bunun kriterler için nasıl ortaya çıktığından da endişeliyim. – MichaelGG

+0

Bunu nasıl ele alacağımı bilmiyorum, ancak yukarıdaki örneğime benzer daha derin bir desen eşleme yapısı kullanabileceğinizi düşündüğümden şüpheliyim. – JasonTrue

İlgili konular