MDrivenServer - how to expose viewmodel as a REST service - mdriven

I use standalone MDrivenServer.
Question - is it possible to expose a viewmodel as a REST service in this configuration without MDrivenTurnkey installation, e.g. using url like ...Rest/Get?command=vmname&id=rootobjref ?
Thank you!

No the MDrivenServer has only the persistence mapper api's exposed. In order to simulate a viewmodel driven rest get-service you can go like this in a MVC application:
Derive your controller from ModelDrivenControllerBase<ESType>
/// <summary>
/// command should match a viewmodel, id should be external id for root or $null$
/// will try and match extra params to viewmodel variables
/// will execute actions on root level
/// will return complete vm on success as json except if string attribute RawJSon is found - then this is returned instead
/// </summary>
public virtual ActionResult Get(string command, string id)
{
Eco.ObjectRepresentation.IModifiableVariableList vars = FindAdditionalRequestParamsAndTreatAsVars();
if (string.IsNullOrEmpty(id))
id = ObjectId.nulltoken;
SaveVariablesToSessionState(command, id, vars);
VMClass onlinevm = CreateVMClassFromName(command, id);
if (onlinevm != null)
{
if (!CheckRestAllowed(onlinevm)) <-- turnkey checks the rest allowed flag
return Content("Must set RestAllowed on VM " + command);
foreach (var col in onlinevm.ViewModelClass.Columns)
{
if (col.IsAction)
{
col.ViewModel.ExecuteAction(col.ViewModelClass.RuntimeName, col.RuntimeName);
}
}
return GetJsonFromVm(onlinevm); <-- this can be implemented with the Tajson concept: https://wiki.mdriven.net/index.php/Tajson
}
else
return Content("Access denied");
}
/// <summary>
/// targetViewRootObject may be both string and IEcoObject.
/// If the newrootAsObject happens to be a guid string - and the IClass has a property guid - then we will try and PS-resolve the guid and use it as root
/// </summary>
protected VMClass CreateVMClassFromName(string targetViewName, object targetViewRootObject)
{
EnsureEcoSpace();
if (targetViewRootObject is string)
targetViewRootObject = SafeObjectForId((string)targetViewRootObject);
VMClass createdVMClass = ViewModelHelper.CreateFromViewModel(targetViewName, EcoSpace, targetViewRootObject as IEcoObject, false);
IEcoObject root = targetViewRootObject as IEcoObject;
if (root == null && createdVMClass.ViewModelClass.IClass is IClass && targetViewRootObject is string)
{
// Handle special case of a GUID as target
// Used to act on direct links for an object
if (targetViewRootObject is string)
{
root = EcoSpace.ExternalIds.ObjectForUnkownId(targetViewRootObject as string, createdVMClass.ViewModelClass.IClass as IClass);
if (root != null)
createdVMClass.Content = root.AsIObject();
}
}
bool vm_visibleDueToAccessGroups = createdVMClass.ViewModelClass.ViewModel.VisibleDueToAccessGroups(EcoSpace, root != null ? root.AsIObject() : null);
if (!vm_visibleDueToAccessGroups)
{
return null;
}
LoadVariablesFromSessionStateIfAvailable(targetViewName, SafeIDForObject(targetViewRootObject), createdVMClass.Variables);
return createdVMClass;
}

Related

How to ensure proxies are created when using the repository pattern with entity framework?

I have this method in my SurveyController class:
public ActionResult AddProperties(int id, int[] propertyids, int page = 1)
{
var survey = _uow.SurveyRepository.Find(id);
if (propertyids == null)
return GetPropertiesTable(survey, page);
var repo = _uow.PropertySurveyRepository;
propertyids.Select(propertyid => new PropertySurvey
{
//Setting the Property rather than the PropertyID
//prevents the error occurring later
//Property = _uow.PropertyRepository.Find(propertyid),
PropertyID = propertyid,
SurveyID = id
})
.ForEach(x => repo.InsertOrUpdate(x));
_uow.Save();
return GetPropertiesTable(survey, page);
}
The GetPropertiesTable redisplays Properties but PropertySurvey.Property is marked virtual and I have created the entity using the new operator, so a proxy to support lazy loading was never created and it is null when I access it. When we have access direct to the DbContext we can use the Create method to explicitly create the proxy. But I have a unit of work and repository pattern here. I guess I could expose the context.Create method via a repository.Create method and then I need to remember to use that instead of the new operator when I add an entity . But wouldn't it be better to encapsulate the problem in my InsertOrUpdate method? Is there some way to detect that the entity being added is not a proxy when it should be and substitute a proxy? This is my InsertOrUpdate method in my base repository class:
protected virtual void InsertOrUpdate(T e, int id)
{
if (id == default(int))
{
// New entity
context.Set<T>().Add(e);
}
else
{
// Existing entity
context.Entry(e).State = EntityState.Modified;
}
}
Based on the answer supplied by qujck. Here is how you can do it without having to employ automapper:
Edited to always check for proxy - not just during insert - as suggested in comments
Edited again to use a different way of checking whether a proxy was passed in to the method. The reason for changing the technique is that I ran into a problem when I introduced an entity that inherited from another. In that case an inherited entity can fail the entity.e.GetType().Equals(instance.GetType() check even if it is a proxy. I got the new technique from this answer
public virtual T InsertOrUpdate(T e)
{
DbSet<T> dbSet = Context.Set<T>();
DbEntityEntry<T> entry;
if (e.GetType().BaseType != null
&& e.GetType().Namespace == "System.Data.Entity.DynamicProxies")
{
//The entity being added is already a proxy type that supports lazy
//loading - just get the context entry
entry = Context.Entry(e);
}
else
{
//The entity being added has been created using the "new" operator.
//Generate a proxy type to support lazy loading and attach it
T instance = dbSet.Create();
instance.ID = e.ID;
entry = Context.Entry(instance);
dbSet.Attach(instance);
//and set it's values to those of the entity
entry.CurrentValues.SetValues(e);
e = instance;
}
entry.State = e.ID == default(int) ?
EntityState.Added :
EntityState.Modified;
return e;
}
public abstract class ModelBase
{
public int ID { get; set; }
}
I agree with you that this should be handled in one place and the best place to catch all looks to be your repository. You can compare the type of T with an instance created by the context and use something like Automapper to quickly transfer all of the values if the types do not match.
private bool mapCreated = false;
protected virtual void InsertOrUpdate(T e, int id)
{
T instance = context.Set<T>().Create();
if (e.GetType().Equals(instance.GetType()))
instance = e;
else
{
//this bit should really be managed somewhere else
if (!mapCreated)
{
Mapper.CreateMap(e.GetType(), instance.GetType());
mapCreated = true;
}
instance = Mapper.Map(e, instance);
}
if (id == default(int))
context.Set<T>().Add(instance);
else
context.Entry(instance).State = EntityState.Modified;
}

PowerShell provider relative path tab-completion issue

I've implemented a simple PowerShell NavigationCmdletProvider.
For those who don't know, this means I can create a snap-in with a cmdlet which is effectively a virtual filesystem drive; this drive can be mounted and navigated into from PowerShell like any normal folder. Each action against the drive (e.g., check if a path points to a valid item, get a list of names of child items in a folder, etc.) is mapped to a method of the .NET class inherited from the NavigationCmdletProvider class.
I'm facing a problem with tab-completion, and would like to find a solution. I've found that tab-completion gives incorrect results when using relative paths. For absolute paths, it works fine.
For those who don't know, tab completion for a NavigationCmdletProvider works through PowerShell calling the GetChildNames method, which is overridden from the NavigationCmdletProvider class.
--Demonstration of the issue--
Assume I have a provider, 'TEST', with the following folder hierarchy:
TEST::child1
TEST::child1\child1a
TEST::child1\child1b
TEST::child2
TEST::child2\child2a
TEST::child2\child2b
TEST::child3
TEST::child3\child3a
TEST::child3\child3b
Absolute paths:
If I type "dir TEST::child1\" and press tab a few times, it gives me the expected results:
> dir TEST::child1\child1a
> dir TEST::child1\child1b
Relative paths:
First, I navigate to "TEST::child1":
> cd TEST::child1
Then, if I type "dirspace" and press tab a few times, it gives me incorrect results:
> dir .\child1\child1a
> dir .\child1\child1b
I expect to see these instead:
> dir .\child1a
> dir .\child1b
Is this a bug in PowerShell, or am I doing something wrong?
Here's the complete, self-contained code for the provider:
[CmdletProvider("TEST", ProviderCapabilities.None)]
public class MyTestProvider : NavigationCmdletProvider
{
private Node m_Root;
private void ConstructTestHierarchy()
{
//
// Create the nodes
//
Node root = new Node("");
Node child1 = new Node("child1");
Node child1a = new Node("child1a");
Node child1b = new Node("child1b");
Node child2 = new Node("child2");
Node child2a = new Node("child2a");
Node child2b = new Node("child2b");
Node child3 = new Node("child3");
Node child3a = new Node("child3a");
Node child3b = new Node("child3b");
//
// Construct node hierarchy
//
m_Root = root;
root.AddChild(child1);
child1.AddChild(child1a);
child1.AddChild(child1b);
root.AddChild(child2);
child2.AddChild(child2a);
child2.AddChild(child2b);
root.AddChild(child3);
child3.AddChild(child3a);
child3.AddChild(child3b);
}
public MyTestProvider()
{
ConstructTestHierarchy();
}
protected override bool IsValidPath(string path)
{
return m_Root.ItemExistsAtPath(path);
}
protected override bool ItemExists(string path)
{
return m_Root.ItemExistsAtPath(path);
}
protected override void GetChildNames(string path, ReturnContainers returnContainers)
{
var children = m_Root.GetItemAtPath(path).Children;
foreach (var child in children)
{
WriteItemObject(child.Name, child.Name, true);
}
}
protected override bool IsItemContainer(string path)
{
return true;
}
protected override void GetChildItems(string path, bool recurse)
{
var children = m_Root.GetItemAtPath(path).Children;
foreach (var child in children)
{
WriteItemObject(child.Name, child.Name, true);
}
}
}
/// <summary>
/// This is a node used to represent a folder inside a PowerShell provider
/// </summary>
public class Node
{
private string m_Name;
private List<Node> m_Children;
public string Name { get { return m_Name; } }
public ICollection<Node> Children { get { return m_Children; } }
public Node(string name)
{
m_Name = name;
m_Children = new List<Node>();
}
/// <summary>
/// Adds a node to this node's list of children
/// </summary>
public void AddChild(Node node)
{
m_Children.Add(node);
}
/// <summary>
/// Test whether a string matches a wildcard string ('*' must be at end of wildcardstring)
/// </summary>
private bool WildcardMatch(string basestring, string wildcardstring)
{
//
// If wildcardstring has no *, just do a string comparison
//
if (!wildcardstring.Contains('*'))
{
return String.Equals(basestring, wildcardstring);
}
else
{
//
// If wildcardstring is really just '*', then any name works
//
if (String.Equals(wildcardstring, "*"))
return true;
//
// Given the wildcardstring "abc*", we just need to test if basestring starts with "abc"
//
string leftOfAsterisk = wildcardstring.Split(new char[] { '*' })[0];
return basestring.StartsWith(leftOfAsterisk);
}
}
/// <summary>
/// Recursively check if "child1\child2\child3" exists
/// </summary>
public bool ItemExistsAtPath(string path)
{
//
// If path is self, return self
//
if (String.Equals(path, "")) return true;
//
// If path has no slashes, test if it matches the child name
//
if(!path.Contains(#"\"))
{
//
// See if any children have this name
//
foreach (var child in m_Children)
{
if (WildcardMatch(child.Name, path))
return true;
}
return false;
}
else
{
//
// Split the path
//
string[] pathChunks = path.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
//
// Take out the first chunk; this is the child we're going to search
//
string nextChild = pathChunks[0];
//
// Combine the rest of the path; this is the path we're going to provide to the child
//
string nextPath = String.Join(#"\", pathChunks.Skip(1).ToArray());
//
// Recurse into child
//
foreach (var child in m_Children)
{
if (String.Equals(child.Name, nextChild))
return child.ItemExistsAtPath(nextPath);
}
return false;
}
}
/// <summary>
/// Recursively fetch "child1\child2\child3"
/// </summary>
public Node GetItemAtPath(string path)
{
//
// If path is self, return self
//
if (String.Equals(path, "")) return this;
//
// If path has no slashes, test if it matches the child name
//
if (!path.Contains(#"\"))
{
//
// See if any children have this name
//
foreach (var child in m_Children)
{
if (WildcardMatch(child.Name, path))
return child;
}
throw new ApplicationException("Child doesn't exist!");
}
else
{
//
// Split the path
//
string[] pathChunks = path.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
//
// Take out the first chunk; this is the child we're going to search
//
string nextChild = pathChunks[0];
//
// Combine the rest of the path; this is the path we're going to provide to the child
//
string nextPath = String.Join(#"\", pathChunks.Skip(1).ToArray());
//
// Recurse into child
//
foreach (var child in m_Children)
{
if (String.Equals(child.Name, nextChild))
return child.GetItemAtPath(nextPath);
}
throw new ApplicationException("Child doesn't exist!");
}
}
}
Not sure this is a bug, I found this workaround that seems to "do the job". (small update, turns out my original code would "bug out" when working your way down multiple levels.
''' <summary>
''' Joins two strings with a provider specific path separator.
''' </summary>
''' <param name="parent">The parent segment of a path to be joined with the child.</param>
''' <param name="child">The child segment of a path to be joined with the parent.</param>
''' <returns>A string that contains the parent and child segments of the path joined by a path separator.</returns>
''' <remarks></remarks>
Protected Overrides Function MakePath(parent As String, child As String) As String
Trace.WriteLine("::MakePath(parent:=" & parent & ",child:=" & child & ")")
Dim res As String = MyBase.MakePath(parent, child)
Trace.WriteLine("::MakePath(parent:=" & parent & ",child:=" & child & ") " & res)
If parent = "." Then
'res = ".\" & child.Split("\").Last
If String.IsNullOrEmpty(Me.SessionState.Path.CurrentLocation.ProviderPath) Then
res = parent & PATH_SEPARATOR & child
Else
res = parent & PATH_SEPARATOR & child.Substring(Me.SessionState.Path.CurrentLocation.ProviderPath.Length + 1)
'res = parent & PATH_SEPARATOR & child.Replace(Me.SessionState.Path.CurrentLocation.ProviderPath & PATH_SEPARATOR, String.Empty)
End If
Trace.WriteLine("::**** TRANSFORM: " & res)
End If
Return res
End Function
You can work around this if you design you provider so that it expects entering a non-empty Root when you create a new drive. I noticed that the tab-completion mistakenly suggest the complete child path instead of just the child name if the Root property of PSDriveInfo has not been set.
It can be limiting for some providers to always require a non-empty root. The workaround above works well if you don't want to make the users always enter some Root when creating a new drive.
I've listed this as a PowerShell provider bug in Microsoft Connect: Issue with relative path tab-completion (via Get-ChildNames) for NavigationCmdletProvider
If anyone can reproduce this, please visit the link and say so, because Microsoft probably won't look into this if only one person is reporting it.
It looks like this is fixed in PowerShell 3.0. I don't know why Microsoft doesn't want to fix this in older versions, it's not something any code could possibly depend on.
I was able to get it to work with overiding string[] ExpandPath(string path) and setting the ProviderCapabilities.ExpandWildcards capabilities.

Entity Framework Detached Object Merging

I have a scenario where I am using Entity Framework in a WCF service, and changes happen on a non-tracked instance of a type that is mapped back to the database via code-first (non-trivial updates and deletes throughout the instance's object tree). When I try to attach the non-tracked instance into the context, EF is only recognizing changes to the simple value types on the root object.
Does anyone know of an elegant solution for this scenario? I am looking for a way to do this by using a generic repository, and avoiding having to run through the instance's entire object tree managing the "attach/detach" state of every object. I have considered possibly using ValueInjecter or AutoMapper to run the changes on a fully hydrated and tracked instance of the "old" state in order for the context to pickup the changes. Also, how would Nhibernate handle this situation?
Thanks in advance for your input!
UPDATE (7/31/2012): I have updated the code to handle genericly-typed keys, and some typing issues with EF Proxies. Also added some helper extensions when dealing with IEntity types. This implementation isn't perfect, but it is very functional.
UPDATE (3/13/2012): I have added a feature request for cleaner merging in EF. The request is located here: http://data.uservoice.com/forums/72025-ado-net-entity-framework-ef-feature-suggestions/suggestions/2679160-better-merging-change-tracking
UPDATE (3/12/2012): I have posted my solution below. It uses FubuCore, ValueInjecter, and requires entities to be marked with one of two interfaces, either IEntity, or IRecursiveEntity for recursive classes. The solution will handle recursive, self-linked entities.
Also, I am referencing a generic repository (Repository) that allows me to get a reference to the IDbSet that EF exposes. This could be substituded with any other generic or specific repository. Lastly, the IEntity interface uses an int? id, however you could define that however you want (Guid/Guid?). The solution itself isn't quite as elegant as I would like, however it allows for much more elegant data access code when behind a physical WCF service boundary.
public class DomainMergeInjection : ConventionInjection
{
private readonly Repository _repository;
private readonly Dictionary<string, object> _potentialParentObjectDump;
private readonly Cache<Type, Type> _entityTypesAndKeysCache;
public DomainMergeInjection(Repository repository)
{
_repository = repository;
_potentialParentObjectDump = new Dictionary<string, object>();
_entityTypesAndKeysCache = new Cache<Type, Type>();
}
protected override bool Match(ConventionInfo c)
{
return c.SourceProp.Name == c.TargetProp.Name;
}
protected override object SetValue(ConventionInfo c)
{
if(c.SourceProp.Value == null)
return null;
//for value types and string just return the value as is
if(c.SourceProp.Type.IsSimple())
return c.SourceProp.Value;
//TODO: Expand on this to handle IList/IEnumerable (i.e. the non-generic collections and arrays).
//handle arrays
if(c.SourceProp.Type.IsArray)
{
var sourceArray = c.SourceProp.Value as Array;
// ReSharper disable PossibleNullReferenceException
var clonedArray = sourceArray.Clone() as Array;
// ReSharper restore PossibleNullReferenceException
for(int index = 0; index < sourceArray.Length; index++)
{
var sourceValueAtIndex = sourceArray.GetValue(index);
//Skip null and simple values that would have already been moved in the clone.
if(sourceValueAtIndex == null || sourceValueAtIndex.GetType().IsSimple())
continue;
// ReSharper disable PossibleNullReferenceException
clonedArray.SetValue(RetrieveComplexSourceValue(sourceValueAtIndex), index);
// ReSharper restore PossibleNullReferenceException
}
return clonedArray;
}
//handle IEnumerable<> also ICollection<> IList<> List<>
if(c.SourceProp.Type.IsGenericEnumerable())
{
var t = c.SourceProp.Type.GetGenericArguments()[0];
if(t.IsSimple())
return c.SourceProp.Value;
var tlist = typeof(List<>).MakeGenericType(t);
dynamic list = Activator.CreateInstance(tlist);
var addMethod = tlist.GetMethod("Add");
foreach(var sourceItem in (IEnumerable)c.SourceProp.Value)
{
addMethod.Invoke(list, new[] { RetrieveComplexSourceValue(sourceItem) });
}
return list;
}
//Get a source value that is in the right state and is tracked if needed.
var itemStateToInject = RetrieveComplexSourceValue(c.SourceProp.Value);
return itemStateToInject;
}
private object RetrieveComplexSourceValue(object source)
{
//If the source is a non-tracked type, or the source is a new value, then return its value.
if(!source.ImplementsIEntity(_entityTypesAndKeysCache) || source.IsEntityIdNull(_entityTypesAndKeysCache))
return source;
object sourceItemFromContext;
//Handle recursive entities, this could probably be cleaned up.
if(source.ImplementsIRecursiveEntity())
{
var itemKey = source.GetEntityIdString(_entityTypesAndKeysCache) + " " + ObjectContext.GetObjectType(source.GetType());
//If we have a context item for this key already, just return it. This solves a recursion problem with self-linking items.
if(_potentialParentObjectDump.ContainsKey(itemKey))
return _potentialParentObjectDump[itemKey];
//Get the source from the context to ensure it is tracked.
sourceItemFromContext = GetSourceItemFromContext(source);
//Add the class into the object dump in order to avoid any infinite recursion issues with self-linked objects
_potentialParentObjectDump.Add(itemKey, sourceItemFromContext);
}
else
//Get the source from the context to ensure it is tracked.
sourceItemFromContext = GetSourceItemFromContext(source);
//Recursively use this injection class instance to inject the source state on to the context source state.
var itemStateToInject = sourceItemFromContext.InjectFrom(this, source);
return itemStateToInject;
}
private object GetSourceItemFromContext(object source)
{
if(source == null)
return null;
//Using dynamic here to "AutoCast" to an IEntity<>. We should have one, but it's important to note just in case.
dynamic sourceEntityValue = source;
var sourceEntityType = ObjectContext.GetObjectType(source.GetType());
var sourceKeyType = sourceEntityType.GetEntityKeyType();
var method = typeof(DomainMergeInjection).GetMethod("GetFromContext", BindingFlags.Instance | BindingFlags.NonPublic);
var generic = method.MakeGenericMethod(sourceEntityType, sourceKeyType);
var sourceItemFromContext = generic.Invoke(this, new object[] { new object[] { sourceEntityValue.Id } });
return sourceItemFromContext;
}
// ReSharper disable UnusedMember.Local
private TItem GetFromContext<TItem, TKey>(object[] keys) where TItem : class, IEntity<TKey>
// ReSharper restore UnusedMember.Local
{
var foundItem = _repository.GetDbSet<TItem>().Find(keys);
return foundItem;
}
}
public static class EntityTypeExtensions
{
/// <summary>
/// Determines if an object instance implements IEntity.
/// </summary>
/// <param name="entity"></param>
/// <param name="entityCache">A cache to hold types that do implement IEntity. If the cache does not have the Type and the Type does implement IEntity, it will add the type to the cache along with the </param>
/// <returns></returns>
public static bool ImplementsIEntity(this object entity, Cache<Type, Type> entityCache = null)
{
//We need to handle getting the proxy type if this is an EF Code-First proxy.
//Please see for more info: http://msdn.microsoft.com/en-us/library/dd456853.aspx
var entityType = ObjectContext.GetObjectType(entity.GetType());
if(entityCache != null && entityCache.Has(entityType))
return true;
var implementationOfIEntity = entityType.GetInterfaces().FirstOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof (IEntity<>));
if(implementationOfIEntity == null)
return false;
if(entityCache != null)
{
var keyType = implementationOfIEntity.GetGenericArguments()[0];
entityCache.Fill(entityType, keyType);
}
return true;
}
/// <summary>
/// Determines if an object instances implements IRecurisveEntity
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public static bool ImplementsIRecursiveEntity(this object entity)
{
//We need to handle getting the proxy type if this is an EF Code-First proxy.
//Please see for more info: http://msdn.microsoft.com/en-us/library/dd456853.aspx
var entityType = ObjectContext.GetObjectType(entity.GetType());
var implementsIRecursiveEntity = entityType.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IRecursiveEntity<>));
return implementsIRecursiveEntity;
}
/// <summary>
/// Determines whether or not an Entity's Id is null. Will throw an exception if a type that does not implement IEntity is passed through.
/// </summary>
/// <param name="entity"></param>
/// <param name="entityCache"></param>
/// <returns></returns>
public static bool IsEntityIdNull(this object entity, Cache<Type, Type> entityCache = null)
{
bool isEntityIdNull = ExecuteEntityIdMethod<bool>("IsEntityIdNull", entity, entityCache);
return isEntityIdNull;
}
/// <summary>
/// Determines whether or not an Entity's Id is null. Will throw an exception if a type that does not implement IEntity is passed through.
/// </summary>
/// <param name="entity"></param>
/// <param name="entityCache"></param>
/// <returns></returns>
public static string GetEntityIdString(this object entity, Cache<Type, Type> entityCache = null)
{
string entityIdString = ExecuteEntityIdMethod<string>("GetEntityIdString", entity, entityCache);
return entityIdString;
}
private static T ExecuteEntityIdMethod<T>(string methodName, object entityInstance, Cache<Type, Type> entityCache = null)
{
if(!entityInstance.ImplementsIEntity(entityCache))
throw new ArgumentException(string.Format("Parameter entity of type {0} does not implement IEntity<>, and so ist not executable for {1}!", entityInstance.GetType(), methodName));
//We need to handle getting the proxy type if this is an EF Code-First proxy.
//Please see for more info: http://msdn.microsoft.com/en-us/library/dd456853.aspx
var entityType = ObjectContext.GetObjectType(entityInstance.GetType());
var keyType = entityCache != null ? entityCache[entityType] : entityType.GetEntityKeyType();
var method = typeof(EntityTypeExtensions).GetMethod(methodName, BindingFlags.Static | BindingFlags.NonPublic);
var generic = method.MakeGenericMethod(keyType);
T returnValue = (T)generic.Invoke(null, new[] { entityInstance });
return returnValue;
}
private static string GetEntityIdString<TKey>(IEntity<TKey> entity)
{
var entityIdString = entity.Id.ToString();
return entityIdString;
}
private static bool IsEntityIdNull<TKey>(IEntity<TKey> entity)
{
//We need to handle getting the proxy type if this is an EF Code-First proxy.
//Please see for more info: http://msdn.microsoft.com/en-us/library/dd456853.aspx
var entityType = ObjectContext.GetObjectType(entity.GetType());
if(entityType.IsPrimitive)
return false;
//NOTE: We know that this entity's type is NOT primitive, therefore we can cleanly test for null, and return properly.
// ReSharper disable CompareNonConstrainedGenericWithNull
var entityIdIsNull = entity.Id == null;
// ReSharper restore CompareNonConstrainedGenericWithNull
return entityIdIsNull;
}
public static Type GetEntityKeyType(this Type typeImplementingIEntity)
{
var implementationOfIEntity = typeImplementingIEntity.GetInterfaces().FirstOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IEntity<>));
if(implementationOfIEntity == null)
throw new ArgumentException(string.Format("Type {0} does not implement IEntity<>", typeImplementingIEntity));
var keyType = implementationOfIEntity.GetGenericArguments()[0];
return keyType;
}
}
public interface IEntity<TKey>
{
TKey Id { get; set; }
}
public interface IRecursiveEntity<TKey> : IEntity<TKey>
{
IRecursiveEntity<TKey> Parent { get; }
IEnumerable<IRecursiveEntity<TKey>> Children { get; }
}
you could use the detached object only as a DTO,
and after refill the object from context with values from the DTO
with ValueInjecter this would be:
//manually
conObj.InjectFrom(dto);
conObj.RefTypeProp.InjectFrom(dto.RefTypeProp);
...
//or by writing a custom injection:
conObj.InjectFrom<ApplyChangesInjection>(dto);
here's the Injection that will do that automatically, (I did it by modifying a bit the DeepClone Injection from VI's home page)
the trick here is that the Injection uses itself in the SetValue method
public class ApplyChangesInjection : ConventionInjection
{
protected override bool Match(ConventionInfo c)
{
return c.SourceProp.Name == c.TargetProp.Name;
}
protected override object SetValue(ConventionInfo c)
{
if (c.SourceProp.Value == null) return null;
//for value types and string just return the value as is
if (c.SourceProp.Type.IsValueType || c.SourceProp.Type == typeof(string))
return c.SourceProp.Value;
//handle arrays - not impl
//handle IEnumerable<> also ICollection<> IList<> List<> - not impl
//for simple object types apply the inject using the corresponding source
return c.TargetProp.Value
.InjectFrom<ApplyChangesInjection>(c.SourceProp.Value);
}
}
//Note: I'm not handling collections in this injection, I just wanted you to understand the principle,
you can look at the original http://valueinjecter.codeplex.com/wikipage?title=Deep%20Cloning&referringTitle=Home

How do I get the old values of an entity?

How do I get the old values of an entity?
follows the example..
public void Update(User user)
ValidateEntity(user, OperationType.Update);
oldUser = (how do I get the old values ​​(database) of the entity User?)
Set.Attach(user);
Context.ObjectStateManager.ChangeObjectState(user, EntityState.Modified);
Context.SaveChanges();
OnUpdated(user, oldUser);
}
Try this:
public void Update(User user)
ValidateEntity(user, OperationType.Update);
var oldUser = Set.Single(u => u.Id == user.Id);
Context.Detach(oldUser);
Set.Attach(user);
Context.ObjectStateManager.ChangeObjectState(user, EntityState.Modified);
Context.SaveChanges();
OnUpdated(user, oldUser);
}
Or this:
public void Update(User user)
{
ValidateEntity(user, OperationType.Update);
var oldUser = Set.Single(u => u.Id == user.Id);
Set.ApplyCurrentValues(user);
Context.SaveChanges(SaveOptions.DetectChangesBeforeSave);
OnUpdated(user, Context.ObjectStateManager.GetOjectStateEntry(user).OriginalValues);
Context.AcceptAllChanges();
}
I found one way of convert DbDataRecord to entity type using reflection...
where http://www.instanceofanobject.com/2011/01/ef4-dbdatarecord-convertto.html
public static class AnonymousTypeConversion
{
///
/// Converts a single DbDataRwcord object into something else.
/// The destination type must have a default constructor.
///
///
///
///
public static T ConvertTo(this DbDataRecord record)
{
T item = Activator.CreateInstance();
for (int f = 0; f
/// Converts a list of DbDataRecord to a list of something else.
///
///
///
///
public static List ConvertTo(this List list)
{
List result = (List)Activator.CreateInstance>();
list.ForEach(rec =>
{
result.Add(rec.ConvertTo());
});
return result;
}
}

Ado.net entity .include() method not working

I've got this function
public static AdoEntity.Inspector GetInspectorWithInclude(int id, List<string> properties)
{
using (var context = new Inspection09Entities())
{
var query = context.Inspector;
if (properties != null)
{
foreach (var prop in properties)
{
if (!string.IsNullOrEmpty(prop))
query.Include(prop);
}
}
return query.Where(i => i.ID == id).First();
}
}
which i use to get my "Inspectors" from the DB and an additional feature to specify what to "Include" with the data. So it takes a List<'string'> and includes them with the query. This function doesn't seem to work because the returned object still does not include the requested data. Could someone tell me what is wrong with this method/approach.
Thanks in advance.
Solution
Thank you to Misha N. suggestion, I have hatched this EF helper which extends the ObjectQuery class. Hopefully others may find it useful.
/// <summary>
/// The include extesion that takes a list and returns a object query with the included data.
/// </summary>
/// <param name="objectQuery">
/// The object query.
/// </param>
/// <param name="includes">
/// The list of strings to include.
/// </param>
/// <typeparam name="T">
/// </typeparam>
/// <returns>
/// An object query of T type with the included data.
/// </returns>
public static ObjectQuery<T> Include<T>(this ObjectQuery<T> objectQuery, List<string> includes)
{
ObjectQuery<T> query = objectQuery;
if (includes != null) includes.ForEach(s => { if (!string.IsNullOrEmpty(s)) query = query.Include(s); });
return query;
}
Usage example.
using(var context = new MyEntity())
{
var includes = new List<string>
{
"Address",
"Orders",
"Invoices"
}
return context.CustomerSet.Include(includes).First(c => c.ID == customerID);
}
Nothing is wrong with your approach, just one little thing need to be changed:
public static AdoEntity.Inspector GetInspectorWithInclude(int id, List<string> properties)
{
using (var context = new Inspection09Entities())
{
var query = context.Inspector;
if (properties != null)
{
foreach (var prop in properties)
{
if (!string.IsNullOrEmpty(prop))
query = query.Include(prop);// <--- HERE
}
}
return query.Where(i => i.ID == id).First();
}
}
ObjectQuery.Include() method is returning altered ObjectQuery object, you haven't been doing changes to the inital query.
Hope this helps