2

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("&", "&amp;")
                    .Replace(",", "&comma;")
                    .Replace("=", "&eq;");
    }

    protected static string MakeUnsafeString(string value)
    {
        if (string.IsNullOrEmpty(value))
            return value;

        return value.Replace("&eq;", "=")
                    .Replace("&comma;", ",")
                    .Replace("&amp;", "&");
    }

    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 クラスの誤ったコード行を変更しました。

4

2 に答える 2

0

必要なのはtype.GetConstructors()nottype.GetConstructor()です。これにより、基本コンストラクターを取得し、探している型を渡すことができます。

于 2013-05-19T10:50:10.517 に答える