public static class AttachExtension
{
public static void AttachGraph(this EntityObject entity, ObjectContext context, Func<ObjectContext> createContext)
{
if (entity == null)
return;
bool b;
entity.AttachGraph(context, createContext, out b);
}
public static void AttachGraph(this EntityObject entity, ObjectContext context, Func<ObjectContext> createContext, out bool isNewEntity)
{
IEnumerable<string> changeProperties;
isNewEntity = entity.IsNewEntity(createContext, out changeProperties);
if (entity.EntityState != EntityState.Detached)
(entity as IEntityWithChangeTracker).SetChangeTracker(null);
AttachOrAddGraph(context, entity, isNewEntity, changeProperties, createContext);
}
private static bool IsNewEntity(this EntityObject entity, Func<object, bool> entityMap)
{
return entityMap(entity);
}
private static bool IsNewEntity(this EntityObject entity, Func<ObjectContext> createContext, out IEnumerable<string> changedProperties)
{
IEnumerable<string> changedPropertiesValue = new string[0];
var value = IsNewEntity(entity, e =>
{
var entityWithKey = (IEntityWithKey)e;
if (entityWithKey.EntityKey == null || entityWithKey.EntityKey.EntityKeyValues == null)
return true;
using (var context2 = createContext())
{
object outEntity;
if (context2.TryGetObjectByKey(entityWithKey.EntityKey, out outEntity))
{
var entity2 = outEntity as EntityObject;
context2.ApplyPropertyChanges(entity2.EntityKey.EntitySetName, entity);
changedPropertiesValue = context2.ObjectStateManager.GetObjectStateEntry(entity2).GetModifiedProperties();
return false;
}
return true;
}
});
changedProperties = changedPropertiesValue;
return value;
}
private static void AttachOrAddGraph(ObjectContext context, EntityObject entity, bool isNewEntity, IEnumerable<string> changedProperties, Func<ObjectContext> createContext)
{
var relatedEntities = entity.RelatedEntities().Where(e => e.Value.Length > 0).ToList();
var relatedEntityKeys = new Dictionary<IRelatedEnd, EntityKey>();
foreach (var relatedEndInfo in relatedEntities)
{
EntityReference entityReference;
if ((entityReference = relatedEndInfo.Key as EntityReference) != null)
relatedEntityKeys.Add(entityReference, entityReference.EntityKey);
foreach (EntityObject relatedEntity in relatedEndInfo.Value)
relatedEndInfo.Key.Remove(relatedEntity);
}
EntityObject entityObject = null;
if (isNewEntity)
context.AddObject(entity.EntitySetName(context), entity);
else
{
entityObject = context.ObjectStateManager.GetObjectStateEntries(EntityState.Added | EntityState.Modified | EntityState.Unchanged).Select(ose => ose.Entity).OfType<EntityObject>().Where(e => e.EntityKey == entity.EntityKey).FirstOrDefault();
if (entityObject == null)
{
context.Attach(entity);
var changedPropertiesEnumerator = changedProperties.GetEnumerator();
if (changedPropertiesEnumerator.MoveNext())
{
var ose = context.ObjectStateManager.GetObjectStateEntry(entity);
ose.SetModified();
do
{
ose.SetModifiedProperty(changedPropertiesEnumerator.Current);
} while (changedPropertiesEnumerator.MoveNext());
}
}
}
foreach (var relatedEndInfo in relatedEntities)
{
if (relatedEndInfo.Value.Any())
foreach (EntityObject relatedEntity in relatedEndInfo.Value)
{
bool relatedEntityIsNew;
relatedEntity.AttachGraph(context, createContext, out relatedEntityIsNew);
if (isNewEntity)
relatedEndInfo.Key.Add(relatedEntity);
else if (relatedEntityIsNew)
{
EntityReference entityReference;
if ((entityReference = relatedEndInfo.Key as EntityReference) != null)
using (var context2 = createContext())
{
AttachOldEntityReference(entity, context, entityReference, (EntityReference)((EntityObject)context2.GetObjectByKey(entity.EntityKey)).RelatedEnds().Where(re => re.RelationshipName == relatedEndInfo.Key.RelationshipName).First());
}
relatedEndInfo.Key.Add(relatedEntity);
}
else
{
using (var context2 = createContext())
{
var entity2 = (EntityObject)context2.GetObjectByKey(entity.EntityKey);
var relatedEnd2 = entity2.RelatedEnds().Where(re => re.RelationshipName == relatedEndInfo.Key.RelationshipName).First();
var association = context2.MetadataWorkspace.GetItemCollection(DataSpace.CSpace).OfType<AssociationType>().Where(at => at.FullName == relatedEndInfo.Key.RelationshipName).First();
bool relationExistsInDB;
if (association.AssociationEndMembers[0].RelationshipMultiplicity == RelationshipMultiplicity.Many && association.AssociationEndMembers[1].RelationshipMultiplicity == RelationshipMultiplicity.Many)
{
var entityCondition = GenerateESQLCondition(entity, "entity");
var relatedCondition = GenerateESQLCondition(relatedEntity, "relatedEntity");
var query = context2.CreateQuery<DbDataRecord>(string.Format("SELECT EXISTS(SELECT 1 FROM entity.{0} AS relatedEntity WHERE {1}) AS RelationExistInDB FROM {2}.{3} AS entity WHERE {4}", context2.MetadataWorkspace.GetItemCollection(DataSpace.CSpace).OfType<EntityType>().Where(at => at.Name == entity.GetType().Name).First().NavigationProperties.First(np => ((AssociationType)np.MetadataProperties.First(mp => mp.Name == "RelationshipType").Value).FullName ==
relatedEnd2.RelationshipName).Name, relatedCondition.Key, context2.DefaultContainerName, entity2.EntityKey.EntitySetName, entityCondition.Key), (entityCondition.Value.Union(relatedCondition.Value)).ToArray());
relationExistsInDB = query.First().GetBoolean(0);
}
else
{
EntityReference entityReference;
if ((entityReference = relatedEndInfo.Key as EntityReference) != null)
AttachOldEntityReference(entity, context, entityReference, (EntityReference)relatedEnd2);
context2.GetObjectByKey(relatedEntity.EntityKey);
relationExistsInDB = relatedEnd2.GetContents().Any(rei => rei.EntityKey == relatedEntity.EntityKey);
}
if (relationExistsInDB)
{
if (entityObject == null)
relatedEndInfo.Key.Attach(relatedEntity);
else
entityObject.RelatedEnds().Where(re => re.RelationshipName == relatedEndInfo.Key.RelationshipName).First().Attach(relatedEntity);
}
else
relatedEndInfo.Key.Add(relatedEntity);
}
}
}
else
{
EntityReference entityReference;
if (!isNewEntity && (entityReference = relatedEndInfo.Key as EntityReference) != null && entityReference.EntityKey == null)
{
using (var context2 = createContext())
{
var entity2 = (EntityObject)context2.GetObjectByKey(entity.EntityKey);
var relatedEnd2 = (EntityReference)entity2.RelatedEnds().Where(re => re.RelationshipName == entityReference.RelationshipName).First();
AttachOldEntityReference(entity, context, entityReference, relatedEnd2);
}
EntityKey outReferenceEntityKey;
if (relatedEntityKeys.TryGetValue(relatedEndInfo.Key, out outReferenceEntityKey))
entityReference.EntityKey = outReferenceEntityKey;
else
entityReference.EntityKey = null;
}
}
}
}
private static void AttachOldEntityReference(EntityObject entity, ObjectContext context, EntityReference entityReference, EntityReference entityReference2)
{
if (entityReference.EntityKey != entityReference2.EntityKey)
{
int associationAdded = context.ObjectStateManager.GetObjectStateEntries(EntityState.Added).Where(ose => ose.EntitySet is AssociationSet).Count();
entityReference.EntityKey = entityReference2.EntityKey;
var q = context.ObjectStateManager.GetObjectStateEntries(EntityState.Added).Where(ose => ose.EntitySet is AssociationSet);
if (q.Count() != associationAdded)
q.Last().AcceptChanges();
}
}
private static KeyValuePair<string, List<ObjectParameter>> GenerateESQLCondition(EntityObject entity, string parameterName)
{
string value = null;
var whereParameters = new List<ObjectParameter>();
foreach (var entityKey in entity.EntityKey.EntityKeyValues)
{
var whereParameterName = string.Concat(parameterName, entityKey.Key);
var condition = string.Format("{0}.{1} = @{2}", parameterName, entityKey.Key, whereParameterName);
whereParameters.Add(new ObjectParameter(whereParameterName, entityKey.Value));
if (value == null)
value = condition;
else
value = string.Concat(" AND ", condition);
}
return new KeyValuePair<string, List<ObjectParameter>>(value, whereParameters);
}
private static IEnumerable<KeyValuePair<IRelatedEnd, EntityObject[]>> RelatedEntities(this EntityObject entity)
{
foreach (var relatedEnd in entity.RelatedEnds())
yield return new KeyValuePair<IRelatedEnd, EntityObject[]>(relatedEnd, relatedEnd.GetContents().ToArray());
}
private static IEnumerable<IRelatedEnd> RelatedEnds(this EntityObject entity)
{
foreach (var relatedEnd in ((IEntityWithRelationships)entity).RelationshipManager.GetAllRelatedEnds())
yield return relatedEnd;
}
private static IEnumerable<EntityObject> GetContents(this IRelatedEnd relatedEnd)
{
foreach (object entity in relatedEnd)
yield return entity as EntityObject;
}
private static string EntitySetName(this EntityObject entity, ObjectContext context)
{
if (entity.EntityKey != null)
return entity.EntityKey.EntitySetName;
return context.MetadataWorkspace.GetItemCollection(DataSpace.CSpace).OfType<EntityContainer>().First().BaseEntitySets.First(es =>
{
var entityTypeMetadata = context.MetadataWorkspace.GetItemCollection(DataSpace.CSpace).OfType<EdmType>().First(ese => ese.Name == entity.GetType().Name);
while (entityTypeMetadata.BaseType != null)
entityTypeMetadata = entityTypeMetadata.BaseType;
return es.ElementType == entityTypeMetadata;
}).Name;
}
}