It is known that ADO.NET Data Services also allows changing
data. For this purpose the data model should have IUpdatable interface. By
means of this interface, data is updating. The LINQ to SQL data model does not
have this interface. This is a matter of a problem.
The reasons of it consist that LINQ-to-SQL platform was
released much earlier than ADO.NET Data Services. As IUpdatable interface is
part of ADO.NET Data Services, it was impossible to implement it in LINQ to SQL
model. To solve this problem, implement IUpdatable as an interface.
Interface IUpdatable should be implemented in a data
context. For these purposes it is possible to create a partial class and to
implement the interface there. We choose a data context; click the right button
of the mouse and choose "View code" item.
Figure 5: Creation of a partial class
After creating a class and setting IUpdatable interface as
base it is possible to receive a stub code as shown in Listing 2.
Listing 2 - Stub code for IUpdatable interface
public partial class CustomersDataContext : IUpdatable
{
public void AddReferenceToCollection(object targetResource, string
propertyName, object resourceToBeAdded)
{
throw new System.NotImplementedException();
}
public void ClearChanges()
{
throw new System.NotImplementedException();
}
public object CreateResource(string containerName, string fullTypeName)
{
throw new System.NotImplementedException();
}
public void DeleteResource(object targetResource)
{
throw new System.NotImplementedException();
}
public object GetResource(System.Linq.IQueryable query, string fullTypeName)
{
throw new System.NotImplementedException();
}
public object GetValue(object targetResource, string propertyName)
{
throw new System.NotImplementedException();
}
public void RemoveReferenceFromCollection(object targetResource,
string propertyName, object resourceToBeRemoved)
{
throw new System.NotImplementedException();
}
public object ResetResource(object resource)
{
throw new System.NotImplementedException();
}
public object ResolveResource(object resource)
{
throw new System.NotImplementedException();
}
public void SaveChanges()
{
throw new System.NotImplementedException();
}
public void SetReference(object targetResource, string propertyName,
object propertyValue)
{
throw new System.NotImplementedException();
}
public void SetValue(object targetResource, string propertyName,
object propertyValue)
{
throw new System.NotImplementedException();
}
}
We can see that IUpdatable interface consists of resource
getting methods, resource creation and resource deletion. It also contains
methods for getting and setting value of a field, creation and deletion of
references and saving changes. Apparently this interface is simple and laconic
enough. We can implement the given interface once and use it for various
models, without dependence on what data is used there.
The following code can be one of the possible
implementations.
Listing 3 - Implementation of IUpdatable interface
partial class CustomersDataContext : IUpdatable
{
public object CreateResource(string containerName, string fullTypeName)
{
Type t = Type.GetType(fullTypeName);
ITable table = (ITable)this.GetType().GetProperty(containerName).
GetValue(this, null);
object resource = Activator.CreateInstance(t);
table.InsertOnSubmit(resource);
return resource;
}
public object GetResource(IQueryable query, string fullTypeName)
{
object resource = null;
foreach (object o in query)
{
if (resource != null)
{
throw new Exception("Expected a single response");
}
resource = o;
}
if ((fullTypeName != null) &&
(resource.GetType() != Type.GetType(fullTypeName)))
{
throw new Exception("Unexpected type for resource");
}
return resource;
}
public object ResetResource(object resource)
{
Type t = resource.GetType();
MetaTable table = this.Mapping.GetTable(t);
object dummyResource = Activator.CreateInstance(t);
foreach (var member in table.RowType.DataMembers)
{
if ((member.IsPrimaryKey == false) && (member.IsDeferred == false) &&
(member.IsAssociation == false) && (member.IsDbGenerated == false))
{
object defaultValue = member.MemberAccessor.
GetBoxedValue(dummyResource);
member.MemberAccessor.SetBoxedValue(ref resource, defaultValue);
}
}
return resource;
}
public void SetValue(object targetResource, string propertyName,
object propertyValue)
{
PropertyInfo pi = targetResource.GetType().GetProperty(propertyName);
if (pi == null)
{
throw new Exception("Can not find property");
}
pi.SetValue(targetResource, propertyValue, null);
}
public object GetValue(object targetResource, string propertyName)
{
PropertyInfo pi = targetResource.GetType().GetProperty(propertyName);
if (pi == null)
{
throw new Exception("Can not find property");
}
return pi.GetValue(targetResource, null);
}
public void SetReference(object targetResource, string propertyName,
object propertyValue)
{
this.SetValue(targetResource, propertyName, propertyValue);
}
public void AddReferenceToCollection(object targetResource,
string propertyName, object resourceToBeAdded)
{
PropertyInfo pi = targetResource.GetType().GetProperty(propertyName);
if (pi == null)
{
throw new Exception("Can not find property");
}
System.Collections.IList collection = (System.Collections.IList)pi.
GetValue(targetResource, null);
collection.Add(resourceToBeAdded);
}
public void RemoveReferenceFromCollection(object targetResource,
string propertyName, object resourceToBeRemoved)
{
PropertyInfo pi = targetResource.GetType().GetProperty(propertyName);
if (pi == null)
{
throw new Exception("Can not find property");
}
System.Collections.IList collection = (IList)pi.
GetValue(targetResource, null);
collection.Remove(resourceToBeRemoved);
}
public void DeleteResource(object targetResource)
{
ITable table = this.GetTable(targetResource.GetType());
table.DeleteOnSubmit(targetResource);
}
public void SaveChanges()
{
this.SubmitChanges();
}
public object ResolveResource(object resource)
{
return resource;
}
public void ClearChanges()
{
}
}