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

在此之上的几层,我有 System 层,其中我有类 Person:

public class Person : Mobile
{
    [Persist]
    public string LastName { get; set; }
}

基本思想是这样的:我希望 System 层对 Data 层几乎一无所知。它创建任何扩展“Mobile”的东西,这些东西会自动保存到数据库中。我不想为 Person 提供一个表,因此会出现奇怪的序列化内容,因为实际上有数百个类可以扩展 Mobile。我不想要数百张桌子。所有这些序列化的东西都可以完美运行,SerializedString 位,保存所有内容,重新加载等等。我唯一没有想出解决方案的是:

我不想为 Person 实现两个构造函数:

public Person() : base() { }

public Person(MobileSerialContainer container)
    : base(container) { }

因为这需要系统层对数据层有更多的了解。

奇怪的序列化字符串仍然存在。反射业务仍然存在。我知道它很慢,但是数据库写入和读取非常罕见,而且无论如何都是异步的。

除此之外,我正在寻找有关如何解决此问题的任何很酷的想法。谢谢!

[编辑] 更改了粘贴在此处的 MobileSerialContainer 类中的错误代码行。

4

2 回答 2

4

如果您正在重写您的应用程序,您可以重新考虑系统的所有设计,以使您的域层(系统层)独立于您的数据访问层,使用:

  • 用于处理对数据库的访问的存储库模式 (dataContext)
  • 您的业​​务对象(移动设备和其他东西)的领域层
  • 控制反转模式 (IOC) 使您的层保持松散耦合

继承的东西绝对不是保持系统松散耦合的好方法。

于 2013-05-19T10:19:10.620 回答
0

您想要的type.GetConstructors()不是type.GetConstructor(),这将使您获得基本构造函数并传递您正在寻找的类型。

于 2013-05-19T10:50:10.517 回答