2011-08-08 24 views
6

Özellik değeri çevirilerini QueryOver sorgularıma dahil etmek istiyorum.Mülk değer dönüşümü NHibernate QueryOver içine nasıl dahil edilir.SelectList?

Doğrudan MVC görünüm modelleri üreten Sorgu Nesne Kalıbı'nı kullanarak sorgu yazmaktan hoşlanırım. Görünüm modellerimde, dönüşüm karmaşıklığını görünümler ve denetleyicilerden uzak tutarak mümkün olduğunca basit mülk türlerini kullanmaya çalışıyorum. Bu, bazen, tarihlerin dizelere dönüştürülmesi gibi, bir türü diğerine dönüştürmem gerekeceği anlamına gelir.

Bu tür dönüşümlerin görünümlerde yapılması gerektiğini söyleyebilirim, ancak görünüm modellerimin çoğu doğrudan JSON nesnelerine dönüştürüldüğünden, dönüşümün çok daha hantal hale gelmesine neden olabilir. JavaScript'te dize dönüşüme tarih yapmak en iyi ihtimalle sorunludur ve JSON çeviricim yeterince esnek değildir. bunun nedeni şu hattın olduğunu Açıkçası

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

:

// 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(); 

sorgu kod çalıştıran aşağıdaki istisnası atılır: Burada

ne yapıyorum bir örnek:

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

Yani soru şu: nasıl sorguya dize dönüştürme tarihini dahil etmek için?

Dönüştürme işlemi gerçekleştirildikten sonra dönüştürme işlemini gerçekleştirmek istemiyorum çünkü sonuçları dönüştürmeden önce sonuçları saklamak için başka bir ara sınıfa ihtiyacım var.

cevap

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(); 

Çalışmalı, ancak maalesef dizinin biçimi üzerinde herhangi bir denetim sağlayamıyorsunuz. Ben biçimlendirilmiş değeri döndürmek için doğru tip ve bir dize özelliği olarak verileri tutan modeli, yani bir özel mülkiyeti tanımlayarak benzer bir sorun ele ettik:

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

Bunun çeşitli avantajları vardır ama işe yaramayabilir JSON dönüştürücü ile iyi. Dönüştürücünüzün özel özellikleri görmezden gelmesine izin verecek bir ayarı veya özniteliği var mı?

+0

Teşekkürler. Takma adıyla ilgili olarak, gerçekten gereksizdir, bu yüzden onu sorudan çıkardım. İlk örneğinizdeki dize dönüşümü, gerçekten buna ihtiyaç duyarken, dize formatı üzerinde hiçbir kontrol bırakmıyor.İkinci önerinizi araştıracağım, yine de bana yardımcı olabilir, ancak yine de görünüm model sınıfı yerine sorgu nesnesinde dönüşümü yapmayı tercih ediyorum. –

+0

İyi şanslar, bir sürü şey denedim ama bu en iyisi. Diğer olasılıklar, özel bir transformatör veya Automapper kullanarak oluşturuyor. –

+0

Çok çirkin ama AFAIK hala işe yarayan tek çözüm. QueryOver'ın, ToString() ile o kadar çok sorun yaşadığının bilincinde ... – Aaronaught

3

Bugün aynı sorunla karşılaştım ve bu ilanı gördü. Devam ettim ve özellik başına tür dönüşümlerini ele almak için Dönüştürücü işlevleri verilebilen kendi transformatörümü oluşturdum.

İşte Transformer sınıfı.

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; } 
} 

Sonra benim sorgu çağırdığınızda üzerinde

, bu Başlat döner ve DateTime değerleri olarak End: Burada

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; 
    } 

Ve ilk benim DTO, bunu nasıl kullanılacağı. Yani çeviriciyi böyle kullanıyorum.

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

Bu yardımcı olur umarım.

+0

Bu çok şık bir çözüm gibi görünüyor! Muhtemelen bu pazarda bir deneyin vereceğim. –

+0

Sevindim Yardımcı olabilirim. Yazmadan önce bunu daha iyi test etmeliydim. Orijinal versiyon, bir dönüştürücü func'in yerini belirlemek için çok agresifti. Şimdi sözlükteki çeviricileri Tuple olarak tuşladım. – NYCChris

İlgili konular