5

Tôi đang xử lý một cơ sở dữ liệu kế thừa có các trường ngày tháng và thời gian như các cột char (8) (định dạng yyyyMMdd và HH: mm: ss, tương ứng) trong một số bảng. Làm thế nào tôi có thể ánh xạ 2 cột char thành một thuộc tính .NET DateTime. Tôi đã thử những điều sau, nhưng tôi nhận được lỗi "không thể truy cập setter" tất nhiên vì các thuộc tính DateTime Date và TimeOfDay là chỉ đọc:Làm thế nào để bạn ánh xạ một thuộc tính DateTime đến 2 cột varchar trong cơ sở dữ liệu với NHibernate (Fluent)?

public class SweetPocoMannaFromHeaven 
{  
    public virtual DateTime? FileCreationDateTime { get; set; } 
} 

.

mapping.Component<DateTime?>(x => x.FileCreationDateTime, 
      dt => 
      { 
       dt.Map(x => x.Value.Date, 
        "file_creation_date"); 
       dt.Map(x => x.Value.TimeOfDay, 
        "file_creation_time"); 
      }); 

Tôi cũng đã thử xác định IUserType cho DateTime, nhưng tôi không thể tìm ra. Tôi đã thực hiện một tấn googling cho một câu trả lời, nhưng tôi không thể tìm ra nó vẫn còn. Lựa chọn nào tốt nhất của tôi để xử lý ngu ngốc quy ước cơ sở dữ liệu kế thừa này? Ví dụ về mã sẽ hữu ích vì không có nhiều tài liệu về một số trường hợp tối nghĩa hơn này.

Trả lời

8

Bạn cần một ICompositeUserType để xử lý nhiều hơn một cột. Bạn cần tăng cường kiểm tra lỗi, định dạng phân tích cú pháp, v.v. nhưng đây là điểm bắt đầu cho bạn.

HTH,
Berryl

public class LegacyDateUserType : ICompositeUserType 
{ 

    public new bool Equals(object x, object y) 
    { 
     if (x == null || y == null) return false; 
     return ReferenceEquals(x, y) || x.Equals(y); 
    } 

    public int GetHashCode(object x) { 
     return x == null ? typeof (DateTime).GetHashCode() + 473 : x.GetHashCode(); 
    } 

    public object NullSafeGet(IDataReader dr, string[] names, ISessionImplementor session, object owner) 
    { 
     if (dr == null) return null; 

     var datePortion = NHibernateUtil.String.NullSafeGet(dr, names[0], session, owner) as string; 
     var timePortion = NHibernateUtil.String.NullSafeGet(dr, names[1], session, owner) as string; 

     var date = DateTime.Parse(datePortion); 
     var time = DateTime.Parse(timePortion); 
     return date.AddTicks(time.Ticks); 
    } 

    ///<summary> 
    /// Write an instance of the mapped class to a prepared statement. Implementors 
    /// should handle possibility of null values. A multi-column type should be written 
    /// to parameters starting from index. 
    ///</summary> 
    public void NullSafeSet(IDbCommand cmd, object value, int index, ISessionImplementor session) { 
     if (value == null) { 
      // whatever 
     } 
     else { 
      var date = (DateTime) value; 
      var datePortion = date.ToString("your date format"); 
      NHibernateUtil.String.NullSafeSet(cmd, datePortion, index, session); 
      var timePortion = date.ToString("your time format"); 
      NHibernateUtil.String.NullSafeSet(cmd, timePortion, index + 1, session); 
     } 
    } 

    public object GetPropertyValue(object component, int property) 
    { 
     var date = (DateTime)component; 
     return property == 0 ? date.ToString("your date format") : date.ToString("your time format"); 
    } 

    public void SetPropertyValue(object component, int property, object value) 
    { 
     throw new NotSupportedException("DateTime is an immutable object."); 
    } 

    public object DeepCopy(object value) { return value; } 

    public object Disassemble(object value, ISessionImplementor session) { return value; } 

    public object Assemble(object cached, ISessionImplementor session, object owner) { return cached; } 

    public object Replace(object original, object target, ISessionImplementor session, object owner) { return original; } 

    ///<summary>Get the "property names" that may be used in a query.</summary> 
    public string[] PropertyNames { get { return new[] { "DATE_PORTION", "TIME_PORTION" }; } } 

    ///<summary>Get the corresponding "property types"</summary> 
    public IType[] PropertyTypes { get { return new IType[] { NHibernateUtil.String, NHibernateUtil.String }; } } 

    ///<summary>The class returned by NullSafeGet().</summary> 
    public Type ReturnedClass { get { return typeof(DateTime); } } 

    ///<summary>Are objects of this type mutable?</summary> 
    public bool IsMutable { get { return false; } } 

} 

=== lập bản đồ thông thạo (giả sử automapping w/classes override) ====

public void Override(AutoMapping<MyClass> m) 
{ 
    .... 
    m.Map(x => x.MyDateTime).CustomType<LegacyDateUserType>(); 
} 
+1

Điều gì sẽ lập bản đồ cho điều này như thế nào? Tôi đã tạo một vài IUserType imnplementations nhưng luôn luôn cho các cặp thuộc tính/cột đơn. Tôi đã tự hỏi những gì kịch bản 'mảng' mảng sẽ có nhiều hơn một phần tử. –

+0

Xin chào Jamie. Bạn chỉ cần liên kết thuộc tính với kiểu tùy chỉnh; trong FNH nó sẽ trông đơn giản như dòng mã tôi thêm vào cuối bài viết của tôi. Nếu kiểu tùy chỉnh phổ biến, bạn có thể thiết lập một quy ước để xử lý nó. Chúc mừng – Berryl

+0

điều này có vẻ tuyệt vời! thx nhiều! tôi sẽ thử nó khi tôi nhận được để làm việc sau này và thiết lập này như là câu trả lời dựa trên thử nghiệm của tôi. – gabe

Các vấn đề liên quan