nHibernate named queries

nHibernate named queries Czasem wymagania biznesowe skłaniają programistów do tworzenia bardzo skomplikowanych powiązań między obiektami / zapytań.
Aby mieć je w jakimś 'przewidywalnym miejscu a nie rozrzucone po kodzie możemy użyć < query/> w mappingu.
Query jest niezależne od Class.
< ?xml version="1.0" ?>
< hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" schema="dbo"  >
  < class name="OH.BusinessObjects.Subject, BusinessObjects" table="Subject" where="IsDeleted = 0" dynamic-update="false" dynamic-insert="false" >
   < id name="ID" column="ID" type="long" unsaved-value="0">
      < generator class="identity"/>
    < / id>
  < / class>

  < query name="qSubjectByName">
       from Subject s
       where s.Name like :name
  < / query>

< / hibernate-mapping>

Wywołanie mogło by być w ten deseń:
IQuery query = Session.GetNamedQuery("qSubjectByName");
query.SetParameter("name","SomeName");
var list = query.List< Subject>();
Ale co jeśli powiązania pomiędzy tabelami nie są tak oczywiste aby móc z nich skorzystać w nHibernate. Być może powiązania są tylko logiczne bez kluczy obcych. Lub nasze zapytanie jest na tyle skomplikowane że warto użyć SQLa aby go zoptymalizować.
Mamy < sql-query />
< ?xml version="1.0" ?>
< hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" schema="dbo"  >
  < class name="OH.BusinessObjects.Subject, BusinessObjects" table="Subject" where="IsDeleted = 0" dynamic-update="false" dynamic-insert="false" >
   < id name="ID" column="ID" type="long" unsaved-value="0">
      < generator class="identity"/>
    < / id>
  < / class>

  < sql-query name="qMediumSubjecList"> 
    < return alias="s" class="OH.BusinessObjects.Subject, BusinessObjects"/> 
    < ![CDATA[
             SELECT s.* 
             FROM Subject s
             inner join SubjectAddress sa on sa.SubjectID = s.ID and s.IsCurrent=1   and s.IsDeleted = 0 and sa.IsDeleted =0
             INNER JOIN Contact c ON sa.SelfInstanceGUID = c.SubjectAddressSelfInstanceGUID and c.IsDeleted=0
             INNER JOIN Medium m on c.MediumID = m.ID and m.IsDeleted =0
             WHERE 
                   m.ID = :mediumID
     ]]> 
  < / sql-query> 
< / hibernate-mapping>

Kluczowe jest [CDATA[ które zawiera dowolne zapytanie SQL.
Kolejnym fajnym elementem jest return któremu z łatwością możemy określić klasę której się spodziewamy jako wyniku.
Wywołanie jest równie łatwe jak poprzednio
   IQuery query = Session.GetNamedQuery("qMediumSubjecList"); 
   query.SetInt64("mediumID", MediumID); 
   var list = query.List< Subject>(); 
Możemy też zwrócić pojedyncze kolumny
 < sql-query name="qSubjectLockingInfo"> 
   < return-scalar column="LastChangeDate" type="datetime"/> 
   < return-scalar column="LockedSessionID" type="Guid"/> 
   < ![CDATA[
            SELECT m.LastChangeDate AS LastChangeDate 
                 , m.LockedSessionID AS LockedSessionID
            FROM Subject m 
            WHERE m.ID = :subjectID
   ]]> 
 < / sql-query>
A jeśli będziemy posiadać klasę z odpowiednimi dwoma propercjami - możemy przetransformować wynik na klasę i transformer.
  public class LockingInfo
    {
        public virtual DateTime LastChangeDate
        {
            get;
            set;
        }

        public virtual Guid? LockedSessionID
        {
            get;
            set;
        }
    }


    public class LockingInfoResultTransformer : IResultTransformer
    {

        #region IResultTransformer Members

        public IList TransformList(IList collection)
        {

            return collection == null ? null : collection.OfType< LockingInfo>().ToList();
        }

        public object TransformTuple(object[] tuple, string[] aliases)
        {
            if (tuple == null || tuple.Length == 0 || aliases == null || aliases.Length == 0)
            {
                return null;
            }

            LockingInfo ret = new LockingInfo();
            for (int i = 0; i < aliases.Length; i++ )
            {
                switch (aliases[i])
                {
                    case "LastChangeDate": ret.LastChangeDate = (DateTime)tuple[i];
                        break;
                    case "LockedSessionID": ret.LockedSessionID = (Guid?)tuple[i];
                        break;
                }
            }
            return ret;
        }

        #endregion
    }
    Query query = session.GetNamedQuery("qSubjectLockingInfo"); 
    query.SetInt64("subjectID", ID); 
    query.SetResultTransformer(new LockingInfoResultTransformer()); 

    LockingInfo lockInfo = query.UniqueResult< LockingInfo>(); 
Na koniec link do dokumentacji tutaj. i słowo o LinqToSQL tuta znajdziemy wpis o nazwanych query w LinqToSQL wydaje się jednak że można to porównać do < query> z nHibbernata, natomiast nie udało mi się znaleźć odpowiednika < sql-query>.

Komentarze

Popularne posty