2011-08-08 9 views
6

मैं अपने प्रश्नोत्तरी प्रश्नों में संपत्ति मूल्य अनुवादों को शामिल करना चाहता हूं।NHibernate QueryOver में संपत्ति मूल्य रूपांतरण को कैसे शामिल करें। चयन सूची?

मुझे क्वेरी ऑब्जेक्ट पैटर्न के बाद क्वेरी लिखना पसंद है, सीधे एमवीसी व्यू मॉडल का उत्पादन। मेरे विचार मॉडल में, मैं उन संपत्ति प्रकारों का उपयोग करने की कोशिश करता हूं जो जितना संभव हो सके, रूपांतरण जटिलता को विचारों और नियंत्रकों से बाहर रखते हुए। इसका मतलब है कि कभी-कभी, मुझे एक प्रकार को दूसरे में परिवर्तित करने की आवश्यकता होगी, जैसे तारों में तिथियां।

कोई तर्क दे सकता है कि ऐसे रूपांतरण विचारों में किए जाने चाहिए लेकिन चूंकि मेरे अधिकांश दृश्य मॉडल सीधे JSON ऑब्जेक्ट्स में अनुवादित होते हैं, जिससे रूपांतरण अधिक बोझिल हो जाता है। जावास्क्रिप्ट में स्ट्रिंग रूपांतरण करने की तारीख सबसे अच्छी समस्या है और मेरा JSON कनवर्टर पर्याप्त लचीला नहीं है।

// Entity. 
public class Customer 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public DateTimeOffset DateCreated { get; set; } 
} 

// View model. 
public class CustomerViewModel 
{ 
    public string Name { get; set; } 
    public string DateCreated { get; set; } // Note the string type here. 
} 

// Query. 
CustomerViewModel model = null; 

List<CustomerViewModel> result = Session.QueryOver<Customer>() 
    .SelectList(list => list 
     .Select(n => n.Name).WithAlias(() => model.Name) 
     .Select(n => n.DateCreated).WithAlias(() => model.DateCreated)) 
    .TransformUsing(Transformers.AliasToBean<CustomerViewModel>()); 
    .Future<CustomerViewModel>() 
    .ToList(); 

क्वेरी कोड चल रहा है, निम्न अपवाद फेंक दिया जाता है:

यहाँ मैं क्या कर रहा हूं, इसका एक उदाहरण

Object of type 'System.DateTimeOffset' cannot be converted to type 'System.String'. 

जाहिर है, इस निम्न पंक्ति की वजह से है:

.Select(n => n.DateCreated).WithAlias(() => model.DateCreated)) 

तो सवाल यह है: कैसे क्वेरी में रूपांतरण स्ट्रिंग करने की तारीख को शामिल करने के लिए?

मैं क्वेरी निष्पादित करने के बाद रूपांतरण निष्पादित नहीं करना चाहता क्योंकि मुझे उन्हें बदलने से पहले परिणामों को संग्रहीत करने के लिए अतिरिक्त इंटरमीडिएट क्लास की आवश्यकता होगी।

उत्तर

9
List<CustomerViewModel> result = Session.QueryOver<Customer>(() => customerAlias) 
    .SelectList(list => list 
     .Select(n => customerAlias.Name).WithAlias(() => model.Name) 
     // I'm not sure if customerAlias works here or why you have declared it at all 
     .Select(Projections.Cast(NHibernateUtil.String, Projections.Property<Customer>(c => c.DateCreated))).WithAlias(() => model.DateCreated)) 
    .TransformUsing(Transformers.AliasToBean<CustomerViewModel>()); 
    .Future<CustomerViewModel>() 
    .ToList(); 

काम करना चाहिए लेकिन दुर्भाग्यवश आपको स्ट्रिंग के प्रारूप पर कोई नियंत्रण नहीं देता है। मैं मॉडल है कि स्वरूपित मान देने के लिए सही प्रकार और एक स्ट्रिंग संपत्ति के रूप में डेटा रखती है, यानी पर एक निजी संपत्ति को परिभाषित करते हुए एक ऐसी ही समस्या संभाला है:

public class CustomerViewModel 
{ 
    public string Name { get; set; } 
    private DateTime DateCreatedImpl { get; set; } 
    public string DateCreated { get { return DateCreatedImpl.ToString(); }} 
} 

यह कई फायदे हैं, लेकिन काम नहीं कर सकते अपने JSON कनवर्टर के साथ अच्छी तरह से। क्या आपके कनवर्टर में एक सेटिंग या विशेषता है जो इसे निजी गुणों को अनदेखा करने की अनुमति देगी?

+0

धन्यवाद। उपनाम के लिए, यह वास्तव में अनिवार्य है इसलिए मैंने इसे प्रश्न से हटा दिया। आपके पहले उदाहरण में स्ट्रिंग रूपांतरण वास्तव में स्ट्रिंग प्रारूप पर कोई नियंत्रण नहीं छोड़ता है, जबकि मुझे वास्तव में इसकी आवश्यकता होती है।मैं आपके दूसरे सुझाव की जांच करने जा रहा हूं, यह मेरी मदद कर सकता है हालांकि मैं अभी भी मॉडल मॉडल के बजाय क्वेरी ऑब्जेक्ट में रूपांतरण करना पसंद करता हूं। –

+0

शुभकामनाएं, मैंने चीजों का एक गुच्छा करने की कोशिश की लेकिन यह सबसे अच्छा है जिसके साथ मैं आया हूं। अन्य संभावनाएं कस्टम ट्रांसफार्मर या ऑटोमैपर का उपयोग कर रही हैं। –

+0

बहुत बदसूरत, लेकिन AFAIK अभी भी एकमात्र समाधान है जो काम करता है। अजीब बात यह है कि QueryOver को 'ToString()' के साथ बहुत परेशानी है, क्योंकि यह वास्तव में एक ही चीज़ पर अनुवाद करता है ... – Aaronaught

3

आज मैं एक ही समस्या में आया, और इस पोस्ट को देखा। मैं आगे बढ़ गया और अपना खुद का ट्रांसफार्मर बनाया जिसे प्रति संपत्ति प्रकार रूपांतरणों को संभालने के लिए कन्वर्टर फ़ंक्शन दिए जा सकते हैं।

यहां ट्रांसफार्मर क्लास है।

public class AliasToDTOTransformer<D> : IResultTransformer where D: class, new() 
{ 
    //Keep a dictionary of converts from Source -> Dest types... 
    private readonly IDictionary<Tuple<Type, Type>, Func<object, object>> _converters; 

    public AliasToDTOTransformer() 
    { 
     _converters = _converters = new Dictionary<Tuple<Type, Type>, Func<object, object>>(); 
    } 

    public void AddConverter<S,R>(Func<S,R> converter) 
    { 
     _converters[new Tuple<Type, Type>(typeof (S), typeof (R))] = s => (object) converter((S) s); 
    } 
    public object TransformTuple(object[] tuple, string[] aliases) 
    { 
     var dto = new D(); 
     for (var i = 0; i < aliases.Length; i++) 
     { 
      var propinfo = dto.GetType().GetProperty(aliases[i]); 
      if (propinfo == null) continue; 
      var valueToSet = ConvertValue(propinfo.PropertyType, tuple[i]); 
      propinfo.SetValue(dto, valueToSet, null); 
     } 
     return dto; 
    } 
    private object ConvertValue(Type destinationType, object sourceValue) 
    { 
     //Approximate default(T) here 
     if (sourceValue == null) 
      return destinationType.IsValueType ? Activator.CreateInstance(destinationType) : null; 

     var sourceType = sourceValue.GetType(); 
     var tuple = new Tuple<Type, Type>(sourceType, destinationType); 
     if (_converters.ContainsKey(tuple)) 
     { 
      var func = _converters[tuple]; 
      return Convert.ChangeType(func.Invoke(sourceValue), destinationType); 
     } 

     if (destinationType.IsAssignableFrom(sourceType)) 
      return sourceValue; 

     return Convert.ToString(sourceValue); // I dunno... maybe throw an exception here instead? 
    } 

    public IList TransformList(IList collection) 
    { 
     return collection; 
    } 

और यहाँ, तो मैं इसका उपयोग है पहले मेरी डीटीओ:

public class EventDetailDTO : DescriptionDTO 
{ 
    public string Code { get; set; } 
    public string Start { get; set; } 
    public string End { get; set; } 
    public int Status { get; set; } 

    public string Comment { get; set; } 
    public int Client { get; set; } 
    public int BreakMinutes { get; set; } 
    public int CanBeViewedBy { get; set; } 
} 

जब मैं अपने क्वेरी फोन पर बाद में, वह प्रारंभ वापस आती है और दिनांक समय मूल्यों के रूप में समाप्त करें। तो इस तरह मैं वास्तव में कनवर्टर का उपयोग करता हूं।

var transformer = new AliasToDTOTransformer<EventDetailDTO>(); 
transformer.AddConverter((DateTime d) => d.ToString("g")); 

उम्मीद है कि इससे मदद मिलती है।

+0

यह एक बहुत ही सुरुचिपूर्ण समाधान की तरह दिखता है! मैं शायद इसे इस रविवार को आज़मा दूंगा। –

+0

खुशी है कि मैं मदद कर सकता हूं। पोस्टिंग से पहले मुझे शायद यह बेहतर परीक्षण करना चाहिए था। कनवर्टर func का पता लगाने में मूल संस्करण आक्रामक था। अब मैं शब्दकोश में कनवर्टर्स को टुपल <सोर्सटाइप, रिटर्न टाइप> के रूप में कुंजी करता हूं – NYCChris

संबंधित मुद्दे