Note that there are some explanatory texts on larger screens.

plurals
  1. POC# Looking for pattern ideas - Inheritance w/ constructor issue
    primarykey
    data
    text
    <p>I have a multiple layered application I'm rewriting using Entity Framework 4 w/ Code First. The important things:</p> <p>In the data layer, on my context, I have:</p> <pre><code>public DbSet&lt;MobileSerialContainer&gt; Mobiles { get; set; } </code></pre> <p>This context has a static instance. I know, I know, terrible practice. There are reasons which aren't relevant to this post as to why I'm doing this.</p> <p>MobileSerialContainer consists of the following:</p> <pre><code>[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)) &amp;&amp; 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); } } </code></pre> <p>Now... I know this is a long post bear with me. Mobile is this:</p> <pre><code>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;", "&amp;amp;") .Replace(",", "&amp;comma;") .Replace("=", "&amp;eq;"); } protected static string MakeUnsafeString(string value) { if (string.IsNullOrEmpty(value)) return value; return value.Replace("&amp;eq;", "=") .Replace("&amp;comma;", ",") .Replace("&amp;amp;", "&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 =&gt; p.Name == name); if (property == null) continue; object rawValue = Convert.ChangeType(value, property.PropertyType); property.SetValue(this, rawValue, null); } } protected IEnumerable&lt;PropertyInfo&gt; PersistentProperties { get { var type = GetType(); var properties = type.GetProperties().Where(p =&gt; p.GetCustomAttributes(typeof(PersistAttribute), true).Any()); return properties; } } } </code></pre> <p>Several layers above this, I have the System layer, in which I have the class Person:</p> <pre><code>public class Person : Mobile { [Persist] public string LastName { get; set; } } </code></pre> <p>The basic idea is this: I want the System layer to have almost no knowledge of the Data layer. It creates anything that extends "Mobile", which is automatically saved to the database. I don't want to have a table for Person, hence the weird serialization stuff, because there are literally hundreds of classes that extend Mobile. I don't want hundreds of tables. All of this serialization stuff works perfectly, the SerializedString bit, saving everything, reloading, etc etc. The only thing I haven't come up with a solution for is:</p> <p>I don't want to have to implement the two constructors to Person:</p> <pre><code>public Person() : base() { } public Person(MobileSerialContainer container) : base(container) { } </code></pre> <p>as that requires the System layer to have more knowledge of the Data layer.</p> <p>The weird serialization string thing stays. The reflection business stays. I know it's slow, but database writes and reads are very rare, and asynchronous anyway.</p> <p>Besides that, I'm looking for any cool ideas about how to resolve this. Thanks!</p> <p>[edit] Changed a miswritten line of code in the MobileSerialContainer class pasted here.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload