//---------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....]
// @backupOwner [....]
//---------------------------------------------------------------------
using System.Collections.Generic;
using System.Data.Common;
using System.Data.Metadata.Edm;
using System.Data.Objects.DataClasses;
using System.Diagnostics;
using System.Collections;
namespace System.Data.Objects
{
// Detached - nothing
// Added - _entity & _currentValues only for shadowState
// Unchanged - _entity & _currentValues only for shadowState
// Unchanged -> Deleted - _entity & _currentValues only for shadowState
// Modified - _currentValues & _modifiedFields + _originalValues only on change
// Modified -> Deleted - _currentValues & _modifiedFields + _originalValues only on change
///
/// Represets either a entity, entity stub or relationship
///
public abstract class ObjectStateEntry : IEntityStateEntry, IEntityChangeTracker
{
#region common entry fields
internal ObjectStateManager _cache;
internal EntitySetBase _entitySet;
internal EntityState _state;
#endregion
#region Constructor
// ObjectStateEntry will not be detached and creation will be handled from ObjectStateManager
internal ObjectStateEntry(ObjectStateManager cache, EntitySet entitySet, EntityState state)
{
Debug.Assert(cache != null, "cache cannot be null.");
_cache = cache;
_entitySet = entitySet;
_state = state;
}
#endregion // Constructor
#region Public members
///
/// ObjectStateManager property of ObjectStateEntry.
///
///
/// ObjectStateManager
public ObjectStateManager ObjectStateManager
{
get
{
ValidateState();
return _cache;
}
}
/// Extent property of ObjectStateEntry.
///
/// Extent
public EntitySetBase EntitySet
{
get
{
ValidateState();
return _entitySet;
}
}
///
/// State property of ObjectStateEntry.
///
///
/// DataRowState
public EntityState State
{
get
{
return _state;
}
internal set
{
_state = value;
}
}
///
/// Entity property of ObjectStateEntry.
///
///
/// The entity encapsulated by this entry.
abstract public object Entity { get; }
///
/// The EntityKey associated with the ObjectStateEntry
///
abstract public EntityKey EntityKey { get; internal set; }
///
/// Determines if this ObjectStateEntry represents a relationship
///
abstract public bool IsRelationship { get; }
///
/// Gets bit array indicating which properties are modified.
///
abstract internal BitArray ModifiedProperties { get; }
BitArray IEntityStateEntry.ModifiedProperties { get { return this.ModifiedProperties; } }
///
/// Original values of entity
///
///
/// DbDataRecord
[DebuggerBrowsable(DebuggerBrowsableState.Never)] // don't have debugger view expand this
abstract public DbDataRecord OriginalValues { get; }
abstract public OriginalValueRecord GetUpdatableOriginalValues();
///
/// Current values of entity/ DataRow
///
///
/// DbUpdatableDataRecord
[DebuggerBrowsable(DebuggerBrowsableState.Never)] // don't have debugger view expand this
abstract public CurrentValueRecord CurrentValues { get; }
///
/// API to accept the current values as original values and mark the entity as Unchanged.
///
///
///
abstract public void AcceptChanges();
///
/// API to mark the entity deleted. if entity is in added state, it will be detached
///
///
///
abstract public void Delete();
///
/// API to return properties that are marked modified
///
///
/// IEnumerable of modified properties names, names are in term of c-space
abstract public IEnumerable GetModifiedProperties();
///
/// set the state to Modified.
///
///
///
/// If State is not Modified or Unchanged
///
abstract public void SetModified();
///
/// Marks specified property as modified.
///
/// This API recognizes the names in terms of OSpace
/// If State is not Modified or Unchanged
///
abstract public void SetModifiedProperty(string propertyName);
///
/// Rejects any changes made to the property with the given name since the property was last loaded,
/// attached, saved, or changes were accepted. The orginal value of the property is stored and the
/// property will no longer be marked as modified.
///
///
/// If the result is that no properties of the entity are marked as modified, then the entity will
/// be marked as Unchanged.
/// Changes to properties can only rejected for entities that are in the Modified or Unchanged state.
/// Calling this method for entities in other states (Added, Deleted, or Detached) will result in
/// an exception being thrown.
/// Rejecting changes to properties of an Unchanged entity or unchanged properties of a Modifed
/// is a no-op.
///
/// The name of the property to change.
abstract public void RejectPropertyChanges(string propertyName);
///
/// Uses DetectChanges to determine whether or not the current value of the property with the given
/// name is different from its original value. Note that this may be different from the property being
/// marked as modified since a property which has not changed can still be marked as modified.
///
///
/// For complex properties, a new instance of the complex object which has all the same property
/// values as the original instance is not considered to be different by this method.
///
/// The name of the property.
/// True if the property has changed; false otherwise.
abstract public bool IsPropertyChanged(string propertyName);
///
/// Returns the RelationshipManager for the entity represented by this ObjectStateEntry.
/// Note that a RelationshipManager objects can only be returned if this entry represents a
/// full entity. Key-only entries (stubs) and entries representing relationships do not
/// have associated RelationshipManagers.
///
/// The entry is a stub or represents a relationship
abstract public RelationshipManager RelationshipManager
{
get;
}
///
/// Changes state of the entry to the specified
///
/// The requested state
abstract public void ChangeState(EntityState state);
///
/// Apply modified properties to the original object.
///
/// object with modified properties
abstract public void ApplyCurrentValues(object currentEntity);
///
/// Apply original values to the entity.
///
/// The object with original values
abstract public void ApplyOriginalValues(object originalEntity);
#endregion // Public members
#region IEntityStateEntry
IEntityStateManager IEntityStateEntry.StateManager
{
get
{
return (IEntityStateManager)this.ObjectStateManager;
}
}
// must explicitly implement this because interface is internal & so is the property on the
// class itself -- apparently the compiler won't let anything marked as internal be part of
// an interface (even if the interface is also internal)
bool IEntityStateEntry.IsKeyEntry
{
get
{
return this.IsKeyEntry;
}
}
#endregion // IEntityStateEntry
#region Public IEntityChangeTracker
///
/// Used to report that a scalar entity property is about to change
/// The current value of the specified property is cached when this method is called.
///
/// The name of the entity property that is changing
void IEntityChangeTracker.EntityMemberChanging(string entityMemberName)
{
this.EntityMemberChanging(entityMemberName);
}
///
/// Used to report that a scalar entity property has been changed
/// The property value that was cached during EntityMemberChanging is now
/// added to OriginalValues
///
/// The name of the entity property that has changing
void IEntityChangeTracker.EntityMemberChanged(string entityMemberName)
{
this.EntityMemberChanged(entityMemberName);
}
///
/// Used to report that a complex property is about to change
/// The current value of the specified property is cached when this method is called.
///
/// The name of the top-level entity property that is changing
/// The complex object that contains the property that is changing
/// The name of the property that is changing on complexObject
void IEntityChangeTracker.EntityComplexMemberChanging(string entityMemberName, object complexObject, string complexObjectMemberName)
{
this.EntityComplexMemberChanging(entityMemberName, complexObject, complexObjectMemberName);
}
///
/// Used to report that a complex property has been changed
/// The property value that was cached during EntityMemberChanging is now added to OriginalValues
///
/// The name of the top-level entity property that has changed
/// The complex object that contains the property that changed
/// The name of the property that changed on complexObject
void IEntityChangeTracker.EntityComplexMemberChanged(string entityMemberName, object complexObject, string complexObjectMemberName)
{
this.EntityComplexMemberChanged(entityMemberName, complexObject, complexObjectMemberName);
}
///
/// Returns the EntityState from the ObjectStateEntry
///
EntityState IEntityChangeTracker.EntityState
{
get
{
return this.State;
}
}
#endregion // IEntityChangeTracker
#region Internal members
abstract internal bool IsKeyEntry { get; }
abstract internal int GetFieldCount(StateManagerTypeMetadata metadata);
abstract internal Type GetFieldType(int ordinal, StateManagerTypeMetadata metadata);
abstract internal string GetCLayerName(int ordinal, StateManagerTypeMetadata metadata);
abstract internal int GetOrdinalforCLayerName(string name, StateManagerTypeMetadata metadata);
abstract internal void RevertDelete();
abstract internal void SetModifiedAll();
abstract internal void EntityMemberChanging(string entityMemberName);
abstract internal void EntityMemberChanged(string entityMemberName);
abstract internal void EntityComplexMemberChanging(string entityMemberName, object complexObject, string complexObjectMemberName);
abstract internal void EntityComplexMemberChanged(string entityMemberName, object complexObject, string complexObjectMemberName);
///
/// Reuse or create a new (Entity)DataRecordInfo.
///
abstract internal DataRecordInfo GetDataRecordInfo(StateManagerTypeMetadata metadata, object userObject);
virtual internal void Reset()
{
_cache = null;
_entitySet = null;
_state = EntityState.Detached;
}
internal void ValidateState()
{
if (_state == EntityState.Detached)
{
throw EntityUtil.ObjectStateEntryinInvalidState();
}
Debug.Assert(null != _cache, "null ObjectStateManager");
Debug.Assert(null != _entitySet, "null EntitySetBase");
}
#endregion // Internal members
}
internal struct StateManagerValue
{
internal StateManagerMemberMetadata memberMetadata;
internal object userObject;
internal object originalValue;
internal StateManagerValue(StateManagerMemberMetadata metadata, object instance, object value)
{
memberMetadata = metadata;
userObject = instance;
originalValue = value;
}
}
internal enum ObjectStateValueRecord
{
OriginalReadonly = 0,
CurrentUpdatable = 1,
OriginalUpdatableInternal = 2,
OriginalUpdatablePublic = 3,
}
// This class is used in Referential Integrity Constraints feature.
// It is used to get around the problem of enumerating dictionary contents,
// but allowing update of the value without breaking the enumerator.
internal sealed class IntBox
{
private int val;
internal IntBox(int val)
{
this.val = val;
}
internal int Value
{
get
{
return val;
}
set
{
val = value;
}
}
}
}