In making a type serializable, we have two options: via attributes such as [Serializable] / [NonSerialized], or by implementing interfaces such as ISerializable and IDeserializationCallback.
It would be nice if we could have the same two options when writing an entity class – either using attributes as in the current DLinq preview – or by implementing a set of interfaces.
This would solve a number of isssues:
- entities could be written whose schema is created at runtime
- a base class for statically typed entities could be designed whose SqlMetal-style generator produces close to parsimonious files
- by implementing an additional interface, an entity could cross remoting or web-services boundary without losing state
Here’s what the basic interfaces could look like:
public interface ICustomEntity
{
IEntitySchema
Schema { get; }
object GetValue
(IEntityMember member);
void SetValue
(IEntityMember member, object
value);
// To bypass normal property
set logic when initially populating:
bool Loading {
get; set; }
}
public interface IEntitySchema
{
bool IsMutable
{ get; }
void
SetImmutable ();
object []
EntityAttributes { get; set; }
object
CreateNewEntity ();
IEntityMemberCollection
Members { get; }
IEntityMember
CreateMember (string name, Type dataType, params
object[] attributes);
}
public interface IEntityMemberCollection : IEnumerable<IEntityMember>
{
IEntityMember
this [string
name] { get; }
bool Contains
(string name);
void Add (IEntityMember member);
}
public interface IEntityMember
{
string Name { get; }
Type
DataType { get; }
object []
MemberAttributes { get; }
}
It would be possible (and fairly easy) to write classes implementing these interfaces that use reflection to obtain the (meta)data from an entity using the current attribute-model. This would allow unification of the two approaches.
But it would also give the developer flexibility to choose a radically different model for entity classes – perhaps one that doesn’t mandate the use of properties. Creating a property at runtime requires use of Reflection.Emit – a horrendously complex animal – as well as creating new app domains.
Runtime Schema
Sometimes its useful to build an entity schema at runtime. One example is a custom query/reporting tool. Another is when supporting two versions of a table undergoing a schema change. A interface-driven approach would allow for this while not precluding attribute-defined schemas for statically typed entities.
Here’s the logic DLinq could use when executing a dynamic query:
- does the entity implement ICustomEntity
- if so, does it have a member for each of the query columns
- if not, is the schema mutable (ie is IsMutable true)
- if so, create and add new members using CreateMember, creating and passing in the standard attributes (such as ColumnAttribute)
- after fully populating the entity, DLinq could call SetImmutable() to prevent further changes to the schema
- the CreateNewEntity method would be used if more than one row was returned from the query, to build an IEnumerable of the original entity. The entity returned by CreateNewEntity would reference a copy of the same (now immutable) schema, so the process of schema population would not need to be repeated for each row.
Crossing Application Domain Boundaries
With the current DLinq model, essential aspects of an entity’s state (such as its original values) are kept in a separate DataContext object, meaning an entity’s state is lost when serialized.
An entity using the interface-based approach could additionally implement the following interface:
public interface IStatefulEntity : ICustomEntity
{
EntityState
EntityState { get; }
object GetValue
(IEntityMember member, EntityVersion
version);
void Delete
();
void
AcceptChanges ();
void
RejectChanges ();
}
public enum EntityState { Loading, Unchanged, Added, Modified,
Deleted }
public enum EntityVersion { Current, Original }
and if this was picked up by the ORM, the entity’s state would be stored within the entity rather than in the DataContext object. The entity could then serialize and deserialize – for instance – from the UI tier to the middle tier – with all appropriate state-information. To maintain object identity, a new DataContext constructor could be defined as follows:
DataContext (IDbConnection cx, params object[] existingEntities)
where existingEntities are deserialized objects returned from another tier.
What
are people’s thoughts on this
Joe Albahari

Interfaces as a solution to n-tier and other issues
inbissachin
And tbh, it would be more for writing 3-tier applications (which is essential) than supporting dynamic schemas (which as you say, can be done, if less elegantly, using other means such as DataSets).
It is interesting the ease at which the preview patches the CSC compiler and Visual Studio - substantially enhancing the language's semantics - without changing the 2.0 CLR. Maybe we will get new languages... although writing a compiler from scratch is no picnic. Especially one that can match C#'s rich interop: it's not often that you need void* but when you do it's pretty damn useful!
shawn3091
Keith, in terms of whether or not to have strongly typed properties, this would merely be optional rather than mandatory if such interfaces were supported. In most instances typed properties make sense. Just like DataSets which can be either strongly typed or have dynamic schema. Designing a system that completely rules out runtime schema seems somewhat inflexible.
Also, dynamic schema is just one application of an interface-based approach. Another is allowing entity state to be tracked across application domain boundaries. For example, assuming MyEntity implements IStatefulSchema, a typed Customer entity might look like this:
public class MyEntity : IStatefulEntity
{
public object GetValue (IEntityMember member) { ... }
// This is the method that allows state to be tracked:
public object GetValue (IEntityMember member, EntityVersion version) ...
public void SetValue (IEntityMember member, object value) {... }
}
public class Customer : MyEntity
{
public static readonly EntityMember<int> CustomerIDMember =
new EntityMember<int> ("CustomerID");
[Column (DbType = "Int NOT NULL IDENTITY", Id = true, AutoGen = true)]
public int CustomerID
{
get { return GetValue (CustomerIDMember); }
set { SetValue (CustomerIDMember, value); }
}
}
or alternatively:
public class Customer : MyEntity
public int CustomerID{
public static readonly EntityMember<int> CustomerIDMember =
new EntityMember<int> ("CustomerID")
{ DbType = "Int NOT NULL IDENTITY", Id = true, AutoGen = true }
{
get { return GetValue (CustomerIDMember); }
set { SetValue (CustomerIDMember, value); }
}
}
This is in fact more strongly typed than the pure attribute-based approach, because one can refer to the customer ID field as follows:
Customer.CustomerIDMember
rather than
typeof (Customer).GetProperty ("CustomerID")
What other solution would you propose for tracking entity state across app domain boundaries Is the problem insoluble
Joe
Vish
Ah, but here's another tidbit -- there has been interest in LINQ among other languages that may be more amenable to this sort of thing. Just because a thing isn't expressable in C# doesn't mean it isn't possible.
For that matter, you could create your own library to create types at runtime and manage the loading and unloading thereof. It just depends on your needs, and such a specialized solution is more viable when it's not in the generalized framework.
charismatic
A bitarray would presume some ordering in the properties, which isn't something I, personally, would feel safe in assuming. You can, however, store a list of the changed members.
Bandwidth may be finite, but I'm not willing to say it's generally scarce for most applications.
Alex1
Speaking for myself...
Something about this screams "lacks compile-time checking" (exactly what we've wanted to fix with LINQ in general, and DLinq in particular), and goes counter to the pre-existing pushback against custom interfaces and attribute-based mapping. This also doesn't look like it'd be compatible with types the developer has no control over (a problem we already have with the PDC bits).
These are a few very significant problems facing any implementation, and in light of those, I'm not certain that what you've proposed would improve the situation.
Obviously you've put some thought into this -- one of the other wins of LINQ is the ability for third parties to implement their own libraries that implement it. It's non-trivial to implement something like DLinq, but it is within your power to create such and show how your mapping solution works in real life and prove my concerns wrong.
Brixi69
In supporting entity state across app domain boundaries, I guess another approach would be for entities to reference the DataContext - which would turn into a lightweight "offline" DataContext upon serialization. Perhaps it would just use internally a BitArray indicating which fields were modified rather than a whole copy of the original data.
Joe
*It's impressive how many things in the Reflection namespaces have been quietly added or tweaked in .NET 2.0 to make life easier!
saileshdev
Re typing: That's the point, though. If you don't want strongly-typed schemas, there are other, perfectly suitable approaches such as DataSet. Remove strong typing and you may as well get rid of the integrated query language altogether, making those who think C#'s getting too complex very happy. (I'm not one of them. There are a few noticeable additions I would like to see happen, personally...)
Re state: Transmitting data across boundaries and maintaining some sort of history on the data has been done in a variety of ways. However, the moment you start imposing a schema, even if the schema is published and freely accessible, you get a lot of people complaining and using the "proprietary" word. The moment you start imposing even something as benign as attributes, you lose people who don't have the ability to modify and recompile classes (which is why other forms of mapping are under consideration).
Further, there's bandwidth efficiency, and how that impacts the options in maintaining state. The ASP.NET story's interesting because you would *like* to keep the entire object state, but there's that pesky ViewState that people want to keep small, with a rather draconian fervor. So why not dump it into the session state That depends on how large your objects are, and just how many of them you plan to maintain. Also, does the use really necessitate maintaining every bit of data
There are many places where Microsoft must comprimise for the less-than-perfect solution in order to satisfy the most common cases. But then, that allows others to sell diametrically opposed approaches to uncommon customers.
C#Thunder
I can see the dilemma. Even with the proprietary issue aside, there's the difficulty in getting consensus on the "right" schema. Nonetheless it seems a shame we can't fully deprecate DataSets.
Thanks for your participation, btw - it's good to have someone interested, even if they don't agree! ;)
Me Myself and I