Entity Framework 4 w/Code First を使用して書き直した多層アプリケーションがあります。重要事項:
私のコンテキストでは、データレイヤーには次のものがあります。
public DbSet<MobileSerialContainer> Mobiles { get; set; }
このコンテキストには静的インスタンスがあります。私は知っています、私は知っています、ひどい練習。私がこれを行っている理由について、この投稿に関係のない理由があります。
MobileSerialContainer は次のもので構成されます。
[Table("Mobiles")]
public sealed class MobileSerialContainer
{
[Key]
public long Serial { get; set; }
[StringLength(32)]
public string Name { get; set; }
public MobileSerialContainer() { }
public MobileSerialContainer(Mobile mobile)
{
Mobile = mobile;
LeContext.Instance.Mobiles.Add(this);
}
[StringLength(1024)]
public string FullClassName
{
get { return Mobile == null ? "" : Mobile.GetType().AssemblyQualifiedName; }
set
{
if (string.IsNullOrEmpty(value) || value == FullClassName)
return;
Mobile = null;
var type = Type.GetType(value);
if (type == null)
return;
if (!type.IsSubclassOf(typeof(Mobile))
&& type != typeof(Mobile))
return;
var constructor = type.GetConstructor(new [] { GetType() });
// The problem here is that Person ( which extends mobile ) does not have a constructor that takes a MobileSerialContainer.
// This is a problem of course, because I want to make this entire layer transparent to the system, so that each derivative
// of Mobile does not have to implement this second constructor. Blasphemy!
if (constructor == null)
return;
Mobile = (Mobile)constructor.Invoke(new object[] { this });
}
}
public string SerializedString
{
get
{
return Mobile == null ? "" : Mobile.Serialize();
}
set
{
if (Mobile == null)
return;
if (string.IsNullOrEmpty(value))
return;
Mobile.Deserialize(value);
}
}
[NotMapped]
public Mobile Mobile { get; set; }
public void Delete()
{
LeContext.Instance.Mobiles.Remove(this);
}
}
今...私はこれが私にとって長い投稿であることを知っています。モバイルはこれです:
public class Mobile
{
public long Serial { get { return Container.Serial; } }
public string Name { get { return Container.Name; } set { Container.Name = value; } }
public Mobile()
{
Container = new MobileSerialContainer(this);
}
public Mobile(MobileSerialContainer container)
{
Container = container;
}
public void Delete()
{
Container.Delete();
}
private MobileSerialContainer Container { get; set; }
protected static string MakeSafeString(string value)
{
if (string.IsNullOrEmpty(value))
return value;
return value.Replace("&", "&")
.Replace(",", ",")
.Replace("=", "&eq;");
}
protected static string MakeUnsafeString(string value)
{
if (string.IsNullOrEmpty(value))
return value;
return value.Replace("&eq;", "=")
.Replace(",", ",")
.Replace("&", "&");
}
public virtual string Serialize()
{
string result = "";
var properties = PersistentProperties;
foreach (var property in properties)
{
string name = MakeSafeString(property.Name);
var value = property.GetValue(this, null);
string unsafeValueString = (string)Convert.ChangeType(value, typeof(string));
string valueString = MakeSafeString(unsafeValueString);
result += name + "=" + valueString + ",";
}
return result;
}
public virtual void Deserialize(string serialized)
{
var properties = PersistentProperties.ToList();
var entries = serialized.Split(',');
foreach (var entry in entries)
{
if (string.IsNullOrEmpty(entry))
continue;
var keyPair = entry.Split('=');
if (keyPair.Length != 2)
continue;
string name = MakeUnsafeString(keyPair[0]);
string value = MakeUnsafeString(keyPair[1]);
var property = properties.FirstOrDefault(p => p.Name == name);
if (property == null)
continue;
object rawValue = Convert.ChangeType(value, property.PropertyType);
property.SetValue(this, rawValue, null);
}
}
protected IEnumerable<PropertyInfo> PersistentProperties
{
get
{
var type = GetType();
var properties = type.GetProperties().Where(p => p.GetCustomAttributes(typeof(PersistAttribute), true).Any());
return properties;
}
}
}
この上にあるいくつかのレイヤーには、Person クラスがある System レイヤーがあります。
public class Person : Mobile
{
[Persist]
public string LastName { get; set; }
}
基本的な考え方は次のとおりです。システム層にはデータ層の知識がほとんどないようにしたいのです。「モバイル」を拡張するものを作成し、データベースに自動的に保存します。モバイルを拡張するクラスは文字通り何百もあるため、Person 用のテーブルを用意したくないため、奇妙なシリアル化が必要になります。何百ものテーブルは必要ありません。このシリアライゼーションのすべて、SerializedString ビット、すべての保存、リロードなどは完全に機能します。
Person に 2 つのコンストラクターを実装する必要はありません。
public Person() : base() { }
public Person(MobileSerialContainer container)
: base(container) { }
それには、システム層がデータ層についてより多くの知識を持っている必要があるためです。
奇妙なシリアル化文字列が残ります。反省事業はそのまま。遅いことはわかっていますが、データベースの書き込みと読み取りは非常にまれであり、とにかく非同期です。
それに加えて、これを解決する方法についてのクールなアイデアを探しています。ありがとう!
[編集] ここに貼り付けた MobileSerialContainer クラスの誤ったコード行を変更しました。