Ado.net entity .include() method not working - entity-framework

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

Related

FlowListView not fully updating UI when changing ObservableCollection<T>

When I remove objects from the list the UI doesn't reflect the current state of the list, normally failling by only one item.
Example: If I remove 4 items, on the UI only shows that I removed 3 items
private ObservableCollection<Card> _cards;
public ObservableCollection<Card> Cards
{
get
{
if (_cards == null)
{
_cards = new ObservableCollection<Card>();
return _cards;
}
return _cards;
}
set
{
SetValue(ref _cards, value);
}
}
My remove method
private void RemoveFromCards(Card card)
{
for (int i = Cards.Count - 1; i >= 0; i--)
{
if (Cards[i].Id == card.Id)
{
Cards.RemoveAt(i);
/* I tried this but doesn't work also
*
*
ObservableCollection<Card> copy = Cards;
copy.RemoveAt(i);
Cards = copy;
*/
}
}
}
Calling remove method
private void RemoveCardsFromView(List<Archive> cards)
{
foreach (Archive a in cards)
{
Card c = new Card {Id = a.CardId};
RemoveFromCards(c);
}
}
Calling code
public async Task RefreshCardsView()
{
if (!CrossConnectivity.Current.IsConnected)
{
BuildToast(false,"No internet connection");
return;
}
try
{
JsonResult cards = (JsonResult) await HttpMiddleman.GetCards();
RemoveCardsFromView(cards.Data.DeletedCards);
AddCardsToView(cards.Data.AddedCards);
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
BuildToast(false,"Could not refresh");
}
}
My binding in FlowListView
<controls:FlowListView x:Name="Board" HasUnevenRows="True"
BackgroundColor="Black"
FlowColumnCount="2"
FlowItemTappedCommand="{Binding ExecuteActionCommand}"
FlowColumnMinWidth="110"
IsPullToRefreshEnabled="True"
IsRefreshing="{Binding IsRefreshing}"
RefreshCommand="{Binding RefreshViewCommand}"
FlowItemsSource="{Binding Cards}"> .....
Thanks in advance guys
make sure that you fire correctly OnPropertyChanged after SetValue() in property statement
and
try with this class (from xamarin) and pass ienumerable of card instead card only object.
Example
private void RemoveFromCards(Card card)
{
Cards.RemoveRange(new []{card});
}
//or directly from
private void RemoveCardsFromView(List<Archive> cards)
{
Cards.RemoveRange(cards.Select(s=> new Card {Id = a.CardId}));
}
/// <summary>
/// Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed.
/// </summary>
/// <typeparam name="T"></typeparam>
public class ObservableRangeCollection<T> : ObservableCollection<T>
{
/// <summary>
/// Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class.
/// </summary>
public ObservableRangeCollection()
: base()
{
}
/// <summary>
/// Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class that contains elements copied from the specified collection.
/// </summary>
/// <param name="collection">collection: The collection from which the elements are copied.</param>
/// <exception cref="System.ArgumentNullException">The collection parameter cannot be null.</exception>
public ObservableRangeCollection(IEnumerable<T> collection)
: base(collection)
{
}
/// <summary>
/// Adds the elements of the specified collection to the end of the ObservableCollection(Of T).
/// </summary>
public void AddRange(IEnumerable<T> collection, NotifyCollectionChangedAction notificationMode = NotifyCollectionChangedAction.Add)
{
if (collection == null)
throw new ArgumentNullException("collection");
CheckReentrancy();
if (notificationMode == NotifyCollectionChangedAction.Reset)
{
foreach (var i in collection)
{
Items.Add(i);
}
OnPropertyChanged(new PropertyChangedEventArgs("Count"));
OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
return;
}
int startIndex = Count;
var changedItems = collection is List<T> ? (List<T>)collection : new List<T>(collection);
foreach (var i in changedItems)
{
Items.Add(i);
}
OnPropertyChanged(new PropertyChangedEventArgs("Count"));
OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, changedItems, startIndex));
}
/// <summary>
/// Removes the first occurence of each item in the specified collection from ObservableCollection(Of T).
/// </summary>
public void RemoveRange(IEnumerable<T> collection)
{
if (collection == null)
throw new ArgumentNullException("collection");
foreach (var i in collection)
Items.Remove(i);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
/// <summary>
/// Clears the current collection and replaces it with the specified item.
/// </summary>
public void Replace(T item)
{
ReplaceRange(new T[] { item });
}
/// <summary>
/// Clears the current collection and replaces it with the specified collection.
/// </summary>
public void ReplaceRange(IEnumerable<T> collection)
{
if (collection == null)
throw new ArgumentNullException("collection");
Items.Clear();
AddRange(collection, NotifyCollectionChangedAction.Reset);
}
}

Entity Framework's 6's `ObjectQuery.EnablePlanCaching` - where is it?

This article explains that query plan caching can be deactivated by setting EnablePlanCaching to false on the ObjectQuery, and also that it is enabled by default in EF6.
Alas, EF6 doesn't have an ObjectQuery, the DbSet's give you DbQuerys.
I don't think I can get an ObjectQuery from the DbQuery, and I certainly don't want to use the old ObjectContext. So is that it or is there a way to disable plan caching in EF6?
Here is an extension method that will let you get an ObjectQuery from the DbSet
using (var ctx = new TestContext())
{
var query = ctx.Products;
query.GetObjectQuery().EnablePlanCaching = false;
var list = query.ToList();
}
namespace Z.EntityFramework.Plus
{
internal static partial class InternalExtensions
{
/// <summary>An IQueryable<TEntity> extension method that get the ObjectQuery from the query.</summary>
/// <typeparam name="T">The type of elements of the query.</typeparam>
/// <param name="query">The query to get the ObjectQuery from.</param>
/// <returns>The ObjectQuery from the query.</returns>
internal static ObjectQuery<T> GetObjectQuery<T>(this IQueryable<T> query)
{
// CHECK for ObjectQuery
var objectQuery = query as ObjectQuery<T>;
if (objectQuery != null)
{
return objectQuery;
}
// CHECK for DbQuery
var dbQuery = query as DbQuery<T>;
if (dbQuery == null)
{
throw new Exception("Oops! A general error has occurred. Please report the issue including the stack trace to our support team: info#zzzprojects.com");
}
var internalQueryProperty = dbQuery.GetType().GetProperty("InternalQuery", BindingFlags.NonPublic | BindingFlags.Instance);
var internalQuery = internalQueryProperty.GetValue(dbQuery, null);
var objectQueryContextProperty = internalQuery.GetType().GetProperty("ObjectQuery", BindingFlags.Public | BindingFlags.Instance);
var objectQueryContext = objectQueryContextProperty.GetValue(internalQuery, null);
objectQuery = objectQueryContext as ObjectQuery<T>;
return objectQuery;
}
}
}

Entity Framework 5. Multiple Include. Is this possible?

I am trying to create a multiple include method in my repository to use as follows:
repository.Include<Post>(x => x.Images, x => x.Tags).First(x => x.Id == 1)
I tried something as:
public IQueryable<T> Include<T>(params Expression<Func<T, Object>>[] paths) where T : class {
return paths.Aggregate(_context.Set<T>(), (x, path) => x.Include(path));
} // Include
But I get the error:
Cannot implicitly convert type 'System.Linq.IQueryable' to 'System.Data.Entity.DbSet'.
Note that the original include is the following:
public static IQueryable Include(
this IQueryable source,
Expression> path
) where T : class;
Can I make this work without turning my repository method into static?
Thank You,
Miguel
If you really want to create your own .Include non-extension method that allows for multiple paths in one call, internally translating to the already provided .Include method, you can do something like
public IQueryable<T> Include<T>(params Expression<Func<T, object>>[] paths)
where T : class
{
IQueryable<T> query = _context.Set<T>();
foreach (var path in paths)
query = query.Include(path);
return query;
}
This is pretty close to what you have already, but avoids the pitfall with Enumerable.Aggregate that you encountered: you'd have the same problem if you replace IQueryable<T> query with var query in my version.
Note that using many .Include may harm performance. If it does in your situation, you can rewrite it to use multiple queries, which you can run one after the other in a transaction.
Personally, as you can call the already provided .Include extension method (using System.Data.Entity;) on any IQueryable, I'd just write it as:
repository.Posts.Include(x => x.Images).Include(x => x.Tags).First(x => x.Id == 1)
public ICollection<SomeClass> Filter(string name, int skip, int take,out int total, params Expression<Func<SomeClass, object>>[] includeProperties) {
IQueryable<SomeClass> query = Session.All<SomeClass>().AsNoTracking();
//query = includeProperties.Aggregate(query, (current, property) => current.Include(property));
foreach (var property in includeProperties){
query = query.Include(property);
}
if (!string.IsNullOrWhiteSpace(name)){
query = query.Where(x => x.Name.Contains(name));
var page = query.OrderBy(x => x.Name)
.Skip(skip)
.Take(take)
.GroupBy(p => new{Total = query.Count()})
.FirstOrDefault();
total = (page != null) ? page.Key.Total : 0;
if (page == null) {
return new List<SomeClass>();
}
return page.ToList();
} else {
var page = query.OrderBy(x => x.Name)
.Skip(skip)
.Take(take)
.GroupBy(p => new { Total = query.Count() })
.FirstOrDefault();
total = (page != null) ? page.Key.Total : 0;
if (page == null) {
return new List<SomeClass>();
}
return page.ToList();
}
}
I guess the shortest way is as follows:
public static class LinqExtensions
{
/// <summary>
/// Acts similar of .Include() LINQ method, but allows to include several object properties at once.
/// </summary>
public static IQueryable<T> IncludeMultiple<T>(this IQueryable<T> query, params Expression<Func<T, object>>[] paths)
where T : class
{
foreach (var path in paths)
query = query.Include(path);
return query;
}
}

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