2016-09-15 13 views
6

Kalıcı mağazaya erişmek için ADO.NET kullanılan eski bir projem var. Şu anda, çok az sayıda kod çoğaltmasıyla birkaç DB sağlayıcısını desteklemek için bunu EF'ye (önemli ise 6.1.3) taşımak istiyorum.EntityFramework kullanarak veritabanındaki varlığın Hashtable özelliği nasıl ele alınır

Hashtable özellik içeren bir işletme vardır: ADO.NET ile

public class Record 
{ 
    ... 
    public Hashtable data { get; set; } 
} 

, BinaryFormatter DAMLA bu data özelliği dönüştürmek için kullanıldı ve tam tersi:

using (MemoryStream stream = new MemoryStream()) 
{ 
    BinaryFormatter formatter = new BinaryFormatter(); 
    formatter.Serialize(stream, data); 
    result = stream.GetBuffer(); 
} 

//---------- 

using (MemoryStream serializationStream = new MemoryStream((byte[])value)) 
{ 
    BinaryFormatter formatter = new BinaryFormatter(); 
    result = (Hashtable)formatter.Deserialize(serializationStream); 
} 

Şimdi EF'e bu özelliği nasıl saklaması ve geri getirmesi gerektiğini söylemem gerekiyor.

public class Record 
{ 
    public byte[] dataRaw { get; set; } 

    [NotMapped] 
    public Hashtable data { 
     get {/*deserialize dataRaw */ } 
     set { /*Serialize to dataRaw*/} 
    } 
} 

Ama bu çözüm hataları eğilimli olduğunu ve o mülkle özel iş akışı takip edilmelidir: Ben varlıktaki bir daha mülkü depolayabilir

denedik ne var

.

Not; Aslında bu soru sadece Hashtable'la ilgili değil, özel bir şekilde saklanması ve geri alınması gereken her özel sınıfla ilgili değil.

+0

dürüst bu mümkün olduğunu düşünmüyorum. Değerin bir sql ilkelinin içine ve dışına itilmesine izin verecek herhangi bir kanca olduğunu düşünmüyorum. Yakın gelebilecek herhangi bir cevap olup olmadığını görmek için bu soruyu merakla bekliyorum. – Jim

+0

benzer bir soru var http://stackoverflow.com/questions/16135642/in-entity-framework-is-there-a-cleaner-way-of-converting-an-object-type-to-a-str, Seninki gibi bir destek alanı kullanıyor. Başka bir yol olduğunu düşünmüyorum. – Jim

cevap

5

Yukarıda bahsettiğim answer temel alınarak tam bir çözüm.
Linqpad'de test ettim ve oldukça iyi çalışıyor.

Özel bir iş akışına ihtiyacınız yoktur, çünkü mülk erişimcileri gerektiğinde hash tablosunu kaydetmeye ve yüklemeye özen gösterir. Değerleri dönüştürmek için

Ana Yöntem

void Main() 
{ 
    using (var ctx = new TestContext()) 
    { 
     var hash = new Hashtable(); 
     hash.Add("A", "A"); 
     ctx.Settings.Add(new Settings { Hash = hash }); 
     ctx.SaveChanges(); 

     // load them up... 
     ctx.Settings.ToArray().Select(_ => _.Hash).Dump(); 
    } 
} 

Ayarlar Sınıf

public class Settings 
{ 
    // a primary key is necessary. 
    public int Id { get; set; } 

    [NotMapped] 
    public Hashtable Hash 
    { 
     get; 
     set; 
    } 

    // the backing field can be protected, this helps 'hide' it. 
    protected virtual byte[] _Hash 
    { 
     get 
     { 
      return Hash.ToBinary(); 
     } 
     set  
     { 
      Hash = value.FromBinary<Hashtable>(); 
     } 
    } 
} 

Uzantıları

public static class Extensions 
{ 

    public static BinaryPropertyConfiguration BinaryProperty<T>(
     this EntityTypeConfiguration<T> mapper, 
     String propertyName) where T : class 
    { 
     Type type = typeof(T); 
     ParameterExpression arg = Expression.Parameter(type, "x"); 
     Expression expr = arg; 

     PropertyInfo pi = type.GetProperty(propertyName, 
      BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance); 
     expr = Expression.Property(expr, pi); 

     LambdaExpression lambda = Expression.Lambda(expr, arg); 

     Expression<Func<T, byte[]>> expression = (Expression<Func<T, byte[]>>)lambda; 
     return mapper.Property(expression); 
    } 

    public static byte[] ToBinary<T>(this T instance) 
    { 
     if (instance == null) 
      return null; 

     using (var stream = new MemoryStream()) 
     { 
      var formatter = new BinaryFormatter(); 
      formatter.Serialize(stream, instance); 
      return stream.ToArray(); 
     } 
    } 

    public static T FromBinary<T>(this byte[] buffer) 
    { 
     if (buffer == null) 
      return default(T); 

     using (var stream = new MemoryStream(buffer, false)) 
     { 
      var formatter = new BinaryFormatter(); 
      var instance = formatter.Deserialize(stream); 
      return (T)instance; 
     } 
    } 
} 

Veri Bağlam

public class TestContext : DbContext 
{ 
    public DbSet<Settings> Settings { get; set; } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     base.OnModelCreating(modelBuilder); 
     modelBuilder 
      .Entity<Settings>() 
      .BinaryProperty("_Hash") 
      .HasColumnName("Hashtable"); 
    }  
} 
+0

_Hash, – Monah

+0

@hadi yea varlık çerçevesiyle çalışacağını merak ediyorum, işe yarıyor, denedim, onu üretilen varyant (max) 'a kaydettim - bu da üretildi ve geri yüklendi - sorun yok. – Jim

+0

@Jim, bu daha zarif bir çözümdür. – stukselbax

İlgili konular