Self-Tracking Entities 序列化的实现
如果你希望能够在 ViewState 中保存 Self-Tracking Entities 对象,那么,将会遇到不能序列化的问题。
Self-Tracking Entities 中生成的类没有序列化的标签,所以,导致使用失败。
幸运的是,Self-Tracking Entities 是通过 T4 - Text Template Transformation Toolkit 来生成代码的。
默认的 Self-Tracking Entities 模板中没有包含我们需要的标记说明来支持序列化,好消息就是我们可以简单的编辑一下 Self-Tracking Entities 的 T4 模板就可以了。
“ADO.NET 自跟踪实体生成器”模板由两个文本模板文件组成:<模型名称>.tt 和 <模型名称>.Context.tt。 <模型名称>.Context.tt 模板生成类型化 ObjectContext。 <模型名称>.tt 模板生成自跟踪实体类型。我们只需要修改<模型名称>.tt即可。
对于T4模板的修改请参照以下文章:http://blogs.msdn.com/b/adonet/archive/2010/05/26/using-binary-serialization-and-viewstate-with-self-tracking-entities.aspx
下面给出一个已经修改好的模板,这个是通用的,可以拷贝使用(其中红色标识的一行数据,需要进行修改,“PRHModel.edmx”修改为自己的实体模型的名称即可)
<#@ template language="C#" debug="false" hostspecific="true"#>
<#@ include file="EF.Utility.CS.ttinclude"#><#@
output extension=".cs"#><#
// Copyright (c) Microsoft Corporation. All rights reserved.
CodeGenerationTools code = new CodeGenerationTools(this);
MetadataLoader loader = new MetadataLoader(this);
CodeRegion region = new CodeRegion(this, 1);
MetadataTools ef = new MetadataTools(this);
string inputFile = @"PRHModel.edmx";
MetadataWorkspace metadataWorkspace = null;
bool allMetadataLoaded =loader.TryLoadAllMetadata(inputFile, out metadataWorkspace);
EdmItemCollection ItemCollection = (EdmItemCollection)metadataWorkspace.GetItemCollection(DataSpace.CSpace);
OriginalValueMembers originalValueMembers = new OriginalValueMembers(allMetadataLoaded, metadataWorkspace, ef);
string namespaceName = code.VsNamespaceSuggestion();
EntityFrameworkTemplateFileManager fileManager = EntityFrameworkTemplateFileManager.Create(this);
// 将支持代码写出到主要模板输出文件
WriteHeader(fileManager);
BeginNamespace(namespaceName, code);
WriteObjectChangeTracker();
WriteIObjectWithChangeTracker();
WriteCustomObservableCollection();
WriteINotifyComplexPropertyChanging();
WriteEqualityComparer();
EndNamespace(namespaceName);
// 发出实体类型
foreach (EntityType entity in ItemCollection.GetItems<EntityType>().OrderBy(e => e.Name))
{
fileManager.StartNewFile(entity.Name + ".cs");
BeginNamespace(namespaceName, code);
WriteEntityTypeSerializationInfo(entity, ItemCollection, code, ef);
#>
[Serializable]
<#=Accessibility.ForType(entity)#> <#=code.SpaceAfter(code.AbstractOption(entity))#>partial class <#=code.Escape(entity)#><#=code.StringBefore(" : ", code.Escape(entity.BaseType))#><#=entity.BaseType == null ? ": " : ", "#>IObjectWithChangeTracker, INotifyPropertyChanged
{
<#
region.Begin("基元属性");
foreach (EdmProperty edmProperty in entity.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == entity))
{
#>
[DataMember]
<#=Accessibility.ForProperty(edmProperty)#> <#=code.Escape(edmProperty.TypeUsage)#> <#=code.Escape(edmProperty)#>
{
<#=code.SpaceAfter(Accessibility.ForGetter(edmProperty))#>get { return <#=code.FieldName(edmProperty)#>; }
<#=code.SpaceAfter(Accessibility.ForSetter(edmProperty))#>set
{
<#
if (((PrimitiveType)edmProperty.TypeUsage.EdmType).PrimitiveTypeKind == PrimitiveTypeKind.Binary &&
(ef.IsKey(edmProperty) || entity.NavigationProperties.Where(np=>np.GetDependentProperties().Contains(edmProperty)).Any()))
{
#>
if (!EqualityComparer.BinaryEquals(<#=code.FieldName(edmProperty)#>, value))
<#
}
else
{
#>
if (<#=code.FieldName(edmProperty)#> != value)
<#
}
#>
{
<#
if (ef.IsKey(edmProperty))
{
string errorMessage = String.Format("属性“{0}”是对象键的一部分,不可更改。仅当未跟踪对象或对象处于“已添加”状态时,才能对键属性进行更改。", edmProperty.Name);
#>
if (ChangeTracker.ChangeTrackingEnabled && ChangeTracker.State != ObjectState.Added)
{
throw new InvalidOperationException("<#=errorMessage#>");
}
<#
}
else if (originalValueMembers.IsOriginalValueMember(edmProperty))
{
#>
ChangeTracker.RecordOriginalValue("<#=edmProperty.Name#>", <#=code.FieldName(edmProperty)#>);
<#
}
bool hasDependentProperties = entity.NavigationProperties.Where(np=>np.GetDependentProperties().Contains(edmProperty)).Any();
if (hasDependentProperties)
{
#>
if (!IsDeserializing)
{
<#
}
foreach (var np in entity.NavigationProperties.Where(np=>np.GetDependentProperties().Contains(edmProperty)))
{
EdmProperty principalProperty = ef.GetCorrespondingPrincipalProperty(np, edmProperty);
if (((PrimitiveType)principalProperty.TypeUsage.EdmType).PrimitiveTypeKind == PrimitiveTypeKind.Binary)
{
#>
if (<#=code.Escape(np)#> != null && !EqualityComparer.BinaryEquals(<#=code.Escape(np)#>.<#=code.Escape(principalProperty)#>, value))
<#
}
else
{
#>
if (<#=code.Escape(np)#> != null && <#=code.Escape(np)#>.<#=code.Escape(principalProperty)#> != value)
<#
}
#>
{
<#
if (!(np.GetDependentProperties().Where(p=>ef.IsNullable(p)).Any() &&
np.GetDependentProperties().Count() > 1))
{
#>
<#=code.Escape(np)#> = null;
<#
}
else
{
#>
var previousValue = <#=code.FieldName(np)#>;
<#=code.FieldName(np)#> = null;
Fixup<#=np.Name#>(previousValue, skipKeys: true);
OnNavigationPropertyChanged("<#=np.Name#>");
<#
}
#>
}
<#
}
if (hasDependentProperties)
{
#>
}
<#
}
#>
<#=code.FieldName(edmProperty)#> = value;
OnPropertyChanged("<#=edmProperty.Name#>");
}
}
}
private <#=code.Escape(edmProperty.TypeUsage)#> <#=code.FieldName(edmProperty)#><#=code.StringBefore(" = ", code.CreateLiteral(edmProperty.DefaultValue))#>;
<#
}
region.End();
region.Begin("复杂属性");
foreach(EdmProperty edmProperty in entity.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == entity))
{
#>
[DataMember]
<#=Accessibility.ForProperty(edmProperty)#> <#=code.Escape(edmProperty.TypeUsage)#> <#=code.Escape(edmProperty)#>
{
<#=code.SpaceAfter(Accessibility.ForGetter(edmProperty))#>get
{
if (!<#=InitializedTrackingField(edmProperty, code)#> && <#=code.FieldName(edmProperty)#> == null)
{
<#=code.FieldName(edmProperty)#> = new <#=code.Escape(edmProperty.TypeUsage)#>();
((INotifyComplexPropertyChanging)<#=code.FieldName(edmProperty)#>).ComplexPropertyChanging += Handle<#=edmProperty.Name#>Changing;
}
<#=InitializedTrackingField(edmProperty, code)#> = true;
return <#=code.FieldName(edmProperty)#>;
}
<#=code.SpaceAfter(Accessibility.ForSetter(edmProperty))#>set
{
<#=InitializedTrackingField(edmProperty, code)#> = true;
if (!Equals(<#=code.FieldName(edmProperty)#>, value))
{
if (<#=code.FieldName(edmProperty)#> != null)
{
((INotifyComplexPropertyChanging)<#=code.FieldName(edmProperty)#>).ComplexPropertyChanging -= Handle<#=edmProperty.Name#>Changing;
}
Handle<#=edmProperty.Name#>Changing(this, null);
<#=code.FieldName(edmProperty)#> = value;
OnPropertyChanged("<#=edmProperty.Name#>");
if (value != null)
{
((INotifyComplexPropertyChanging)<#=code.FieldName(edmProperty)#>).ComplexPropertyChanging += Handle<#=edmProperty.Name#>Changing;
}
}
}
}
private <#=code.Escape(edmProperty.TypeUsage)#> <#=code.FieldName(edmProperty)#>;
private bool <#=InitializedTrackingField(edmProperty, code)#>;
<#
}
region.End();
////////
//////// 写入导航属性 -------------------------------------------------------------------------------------------
////////
region.Begin("导航属性");
foreach (NavigationProperty navProperty in entity.NavigationProperties.Where(np => np.DeclaringType == entity))
{
NavigationProperty inverse = ef.Inverse(navProperty);
if (inverse != null && !IsReadWriteAccessibleProperty(inverse))
{
inverse = null;
}
#>
[DataMember]
<#
if (navProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many)
{
#>
<#=Accessibility.ForReadOnlyProperty(navProperty)#> TrackableCollection<<#=code.Escape(navProperty.ToEndMember.GetEntityType())#>> <#=code.Escape(navProperty)#>
{
get
{
if (<#=code.FieldName(navProperty)#> == null)
{
<#=code.FieldName(navProperty)#> = new TrackableCollection<<#=code.Escape(navProperty.ToEndMember.GetEntityType())#>>();
<#=code.FieldName(navProperty)#>.CollectionChanged += Fixup<#=navProperty.Name#>;
}
return <#=code.FieldName(navProperty)#>;
}
set
{
if (!ReferenceEquals(<#=code.FieldName(navProperty)#>, value))
{
if (ChangeTracker.ChangeTrackingEnabled)
{
throw new InvalidOperationException("当启用 ChangeTracking 时,无法设置 FixupChangeTrackingCollection");
}
if (<#=code.FieldName(navProperty)#> != null)
{
<#=code.FieldName(navProperty)#>.CollectionChanged -= Fixup<#=navProperty.Name#>;
<#
if (ef.IsCascadeDeletePrincipal(navProperty))
{
#>
// 这是执行级联删除的关联中的主体端。
// 移除当前集合中所有实体的级联删除事件处理程序。
foreach (<#=code.Escape(navProperty.ToEndMember.GetEntityType())#> item in <#=code.FieldName(navProperty)#>)
{
ChangeTracker.ObjectStateChanging -= item.HandleCascadeDelete;
}
<#
}
#>
}
<#=code.FieldName(navProperty)#> = value;
if (<#=code.FieldName(navProperty)#> != null)
{
<#=code.FieldName(navProperty)#>.CollectionChanged += Fixup<#=navProperty.Name#>;
<#
if (ef.IsCascadeDeletePrincipal(navProperty))
{
#>
// 这是执行级联删除的关联中的主体端。
// 为新集合中已存在的所有实体添加级联删除事件处理程序。
foreach (<#=code.Escape(navProperty.ToEndMember.GetEntityType())#> item in <#=code.FieldName(navProperty)#>)
{
ChangeTracker.ObjectStateChanging += item.HandleCascadeDelete;
}
<#
}
#>
}
OnNavigationPropertyChanged("<#=navProperty.Name#>");
}
}
}
private TrackableCollection<<#=code.Escape(navProperty.ToEndMember.GetEntityType())#>> <#=code.FieldName(navProperty)#>;
<#
}
else
{
#>
<#=Accessibility.ForProperty(navProperty)#> <#=code.Escape(navProperty.ToEndMember.GetEntityType())#> <#=code.Escape(navProperty)#>
{
<#=code.SpaceAfter(Accessibility.ForGetter(navProperty))#>get { return <#=code.FieldName(navProperty)#>; }
<#=code.SpaceAfter(Accessibility.ForSetter(navProperty))#>set
{
if (!ReferenceEquals(<#=code.FieldName(navProperty)#>, value))
{
<#
// 如果这是识别关系的依赖端,则仅当依赖处于“已添加”状态且主体的键与依赖上的外键匹配时,才能更改主体端
if (ef.IsPrincipalEndOfIdentifyingRelationship((AssociationEndMember)navProperty.ToEndMember))
{
#>
if (ChangeTracker.ChangeTrackingEnabled && ChangeTracker.State != ObjectState.Added && value != null)
{
<#
List<EdmProperty> dependents = navProperty.GetDependentProperties().ToList();
int dependentCount = dependents.Count;
StringBuilder keyMatchCondition = new StringBuilder();
for (int i = 0; i < dependentCount; i++)
{
EdmProperty dependentProperty = dependents[i];
EdmProperty principalProperty = ef.GetCorrespondingPrincipalProperty(navProperty, dependentProperty);
string escapedDependent = code.Escape(dependentProperty);
string escapedPrincipal = code.Escape(principalProperty);
if (i > 0)
{
keyMatchCondition.AppendFormat(" || ");
}
string equality = null;
if (((PrimitiveType)principalProperty.TypeUsage.EdmType).PrimitiveTypeKind == PrimitiveTypeKind.Binary)
{
equality = "!EqualityComparer.BinaryEquals({0}, value.{1})";
}
else
{
equality = "{0} != value.{1}";
}
keyMatchCondition.AppendFormat(CultureInfo.InvariantCulture, equality, escapedDependent, escapedPrincipal);
}
#>
// 这是识别关系的依赖端,因此主体端在设置后不能更改,
// 否则它只能设置为主键值与依赖外键相同的实体。
if (<#=keyMatchCondition.ToString()#>)
{
throw new InvalidOperationException("仅当依赖端处于“已添加”状态时,才能更改识别关系的主体端。");
}
}
<#
}
#>
var previousValue = <#=code.FieldName(navProperty)#>;
<#=code.FieldName(navProperty)#> = value;
Fixup<#=navProperty.Name#>(previousValue);
OnNavigationPropertyChanged("<#=navProperty.Name#>");
}
}
}
private <#=code.Escape(navProperty.ToEndMember.GetEntityType())#> <#=code.FieldName(navProperty)#>;
<#
}
}
region.End();
region.Begin("ChangeTracking");
if (entity.BaseType == null)
{
#>
protected virtual void OnPropertyChanged(String propertyName)
{
if (ChangeTracker.State != ObjectState.Added && ChangeTracker.State != ObjectState.Deleted)
{
ChangeTracker.State = ObjectState.Modified;
}
if (_propertyChanged != null)
{
_propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
protected virtual void OnNavigationPropertyChanged(String propertyName)
{
if (_propertyChanged != null)
{
_propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged{ add { _propertyChanged += value; } remove { _propertyChanged -= value; } }
private event PropertyChangedEventHandler _propertyChanged;
private ObjectChangeTracker _changeTracker;
[DataMember]
public ObjectChangeTracker ChangeTracker
{
get
{
if (_changeTracker == null)
{
_changeTracker = new ObjectChangeTracker();
_changeTracker.ObjectStateChanging += HandleObjectStateChanging;
}
return _changeTracker;
}
set
{
if(_changeTracker != null)
{
_changeTracker.ObjectStateChanging -= HandleObjectStateChanging;
}
_changeTracker = value;
if(_changeTracker != null)
{
_changeTracker.ObjectStateChanging += HandleObjectStateChanging;
}
}
}
private void HandleObjectStateChanging(object sender, ObjectStateChangingEventArgs e)
{
if (e.NewState == ObjectState.Deleted)
{
ClearNavigationProperties();
}
}
<#
// 如果此实体类型参与另一端定义了 OnDelete
// 级联删除的任何关系,或者如果它是任何识别关系中的依赖,则需要
// 事件处理程序来处理在删除父级时激发的通知。
if (ItemCollection.GetItems<AssociationType>().Where(a =>
((RefType)a.AssociationEndMembers[0].TypeUsage.EdmType).ElementType == entity && ef.IsCascadeDeletePrincipal(a.AssociationEndMembers[1]) ||
((RefType)a.AssociationEndMembers[1].TypeUsage.EdmType).ElementType == entity && ef.IsCascadeDeletePrincipal(a.AssociationEndMembers[0])).Any())
{
#>
// 此实体类型是至少一个执行级联删除的关联中的依赖端。
// 此事件处理程序将处理在删除主体端时发生的通知。
internal void HandleCascadeDelete(object sender, ObjectStateChangingEventArgs e)
{
if (e.NewState == ObjectState.Deleted)
{
this.MarkAsDeleted();
}
}
<#
}
#>
protected bool IsDeserializing { get; private set; }
[OnDeserializing]
public void OnDeserializingMethod(StreamingContext context)
{
IsDeserializing = true;
}
<#
}
foreach(EdmProperty edmProperty in entity.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == entity))
{
#>
// <#=String.Format(CultureInfo.CurrentCulture, "记录复杂属性 {0} 的原始值", edmProperty.Name)#>
private void Handle<#=edmProperty.Name#>Changing(object sender, EventArgs args)
{
if (ChangeTracker.State != ObjectState.Added && ChangeTracker.State != ObjectState.Deleted)
{
ChangeTracker.State = ObjectState.Modified;
}
<#
if (originalValueMembers.IsOriginalValueMember(edmProperty))
{
#>
<#=code.Escape(edmProperty.TypeUsage)#>.RecordComplexOriginalValues("<#=edmProperty.Name#>", this.<#=code.Escape(edmProperty)#>, ChangeTracker);
<#
}
#>
}
<#
}
List<AssociationEndMember> shadowAssociationEnds = new List<AssociationEndMember>();
foreach(var association in ItemCollection.GetItems<AssociationType>().Where(x => !IsForeignKeyOrIdentifyingRelationship(ef, x) &&
((((RefType)x.AssociationEndMembers[0].TypeUsage.EdmType).ElementType == entity &&
x.AssociationEndMembers[0].RelationshipMultiplicity != RelationshipMultiplicity.One &&
x.AssociationEndMembers[1].RelationshipMultiplicity != RelationshipMultiplicity.Many) ||
((RefType)x.AssociationEndMembers[1].TypeUsage.EdmType).ElementType == entity &&
x.AssociationEndMembers[1].RelationshipMultiplicity != RelationshipMultiplicity.One &&
x.AssociationEndMembers[0].RelationshipMultiplicity != RelationshipMultiplicity.Many)))
{
if (!entity.NavigationProperties.Any(x => x.RelationshipType == association))
{
for (int i = 0; i < 2; i++)
{
int targetRoleIndex = 0;
if (((RefType)association.AssociationEndMembers[i].TypeUsage.EdmType).ElementType == entity)
{
targetRoleIndex = (i + 1) % 2;
shadowAssociationEnds.Add(association.AssociationEndMembers[targetRoleIndex]);
}
}
}
}
#>
[OnDeserialized]
public <#=entity.BaseType == null ? "" : "new " #>void OnDeserializedMethod(StreamingContext context)
{
<#
if (entity.BaseType == null)
{
#>
IsDeserializing = false;
ChangeTracker.ChangeTrackingEnabled = true;
<#
}
else
{
#>
base.OnDeserializedMethod(context);
<#
}
#>
<#
// Hook up ComplexType property event handlers
foreach(EdmProperty edmProperty in entity.Properties
.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == entity))
{
#>
if (<#=code.FieldName(edmProperty)#> != null)
{
((INotifyComplexPropertyChanging)<#=code.FieldName(edmProperty)#>)
.ComplexPropertyChanging -= Handle<#=edmProperty.Name#>Changing;
((INotifyComplexPropertyChanging)<#=code.FieldName(edmProperty)#>)
.ComplexPropertyChanging += Handle<#=edmProperty.Name#>Changing;
}
<#
}
// Hook up Collection property event handlers
foreach (NavigationProperty navProperty in entity.NavigationProperties
.Where(np => np.DeclaringType == entity))
{
if (navProperty.ToEndMember.RelationshipMultiplicity ==
RelationshipMultiplicity.Many)
{
#>
if (<#=code.FieldName(navProperty)#> != null)
{
<#=code.FieldName(navProperty)#>.CollectionChanged -= Fixup<#=navProperty.Name#>;
<#=code.FieldName(navProperty)#>.CollectionChanged += Fixup<#=navProperty.Name#>;
<#
if (ef.IsCascadeDeletePrincipal(navProperty))
{
#>
// This is the principal end in an association that performs cascade deletes.
// Add the cascade delete event handler for any entities that are
// already in the collection.
foreach (var item in <#=code.FieldName(navProperty)#>)
{
ChangeTracker.ObjectStateChanging -= item.HandleCascadeDelete;
ChangeTracker.ObjectStateChanging += item.HandleCascadeDelete;
}
<#
}
#>
}
<#
}
}
#>
}
protected <#=entity.BaseType == null ? "virtual " : "override " #>void ClearNavigationProperties()
{
<#
if (entity.BaseType != null)
{
#>
base.ClearNavigationProperties();
<#
}
foreach (NavigationProperty navProperty in entity.NavigationProperties.Where(np => np.DeclaringType == entity))
{
if (navProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many)
{
#>
<#=code.Escape(navProperty)#>.Clear();
<#
}
else
{
#>
<#=code.Escape(navProperty)#> = null;
<#
if (IsSaveReference(ef, navProperty))
{
#>
Fixup<#=navProperty.Name#>Keys();
<#
}
}
}
foreach(var associationEnd in shadowAssociationEnds)
{
AssociationType association = associationEnd.DeclaringType as AssociationType;
#>
<#=CreateFixupMethodName(associationEnd)#>(null, true);
<#
}
#>
}
<#
region.End();
region.Begin("关联修复");
foreach (NavigationProperty navProperty in entity.NavigationProperties.Where(np => np.DeclaringType == entity))
{
NavigationProperty inverse = ef.Inverse(navProperty);
if (inverse != null && !IsReadWriteAccessibleProperty(inverse))
{
inverse = null;
}
if (navProperty.ToEndMember.RelationshipMultiplicity != RelationshipMultiplicity.Many)
{
var skipKeysArgument = navProperty.GetDependentProperties().Where(p=>ef.IsNullable(p)).Any()
? ", bool skipKeys = false"
: String.Empty;
#>
private void Fixup<#=navProperty.Name#>(<#=code.Escape(navProperty.ToEndMember.GetEntityType())#> previousValue<#= skipKeysArgument #>)
{
<#
if (ef.IsCascadeDeletePrincipal(navProperty))
{
#>
// 这是执行级联删除的关联中的主体端。
// 更新事件侦听器以引用新依赖。
if (previousValue != null)
{
ChangeTracker.ObjectStateChanging -= previousValue.HandleCascadeDelete;
}
if (<#=code.Escape(navProperty)#> != null)
{
ChangeTracker.ObjectStateChanging += <#=code.Escape(navProperty)#>.HandleCascadeDelete;
}
<#
}
else if (inverse == null && ef.IsCascadeDeletePrincipal((AssociationEndMember)navProperty.ToEndMember))
{
#>
// 这是执行级联删除的关联中的依赖端。
// 更新主体的事件侦听器以引用新依赖。
// 这是从依赖到主体的单向关系,因此依赖端
// 负责管理级联删除事件处理程序。在所有其他情况下,主体端会管理该处理程序。
if (previousValue != null)
{
previousValue.ChangeTracker.ObjectStateChanging -= HandleCascadeDelete;
}
if (<#=code.Escape(navProperty)#> != null)
{
<#=code.Escape(navProperty)#>.ChangeTracker.ObjectStateChanging += HandleCascadeDelete;
}
<#
}
#>
if (IsDeserializing)
{
return;
}
<#
if (inverse != null)
{
if (inverse.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many)
{
#>
if (previousValue != null && previousValue.<#=code.Escape(inverse)#>.Contains(this))
{
previousValue.<#=code.Escape(inverse)#>.Remove(this);
}
<#
}
else
{
#>
if (previousValue != null && ReferenceEquals(previousValue.<#=code.Escape(inverse)#>, this))
{
previousValue.<#=code.Escape(inverse)#> = null;
}
<#
}
if (inverse.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many)
{
#>
if (<#=code.Escape(navProperty)#> != null)
{
if (!<#=code.Escape(navProperty)#>.<#=code.Escape(inverse)#>.Contains(this))
{
<#=code.Escape(navProperty)#>.<#=code.Escape(inverse)#>.Add(this);
}
<#
foreach (var dependentProperty in navProperty.GetDependentProperties())
{
#>
<#=code.Escape(dependentProperty)#> = <#=code.Escape(navProperty)#>.<#=code.Escape(ef.GetCorrespondingPrincipalProperty(navProperty, dependentProperty))#>;
<#
}
#>
}
<#
if (navProperty.GetDependentProperties().Where(p=>ef.IsNullable(p)).Any())
{
#>
else if (!skipKeys)
{
<#
foreach (var dependentProperty in navProperty.GetDependentProperties().Where(p => ef.IsNullable(p)))
{
#>
<#=code.Escape(dependentProperty)#> = null;
<#
}
#>
}
<#
}
}
else
{
#>
if (<#=code.Escape(navProperty)#> != null)
{
<#=code.Escape(navProperty)#>.<#=code.Escape(inverse)#> = this;
<#
foreach (var dependentProperty in navProperty.GetDependentProperties())
{
#>
<#=code.Escape(dependentProperty)#> = <#=code.Escape(navProperty)#>.<#=code.Escape(ef.GetCorrespondingPrincipalProperty(navProperty, dependentProperty))#>;
<#
}
#>
}
<#
}
}
else
{
if (navProperty.GetDependentProperties().Any())
{
#>
if (<#=code.Escape(navProperty)#> != null)
{
<#
foreach (var dependentProperty in navProperty.GetDependentProperties())
{
#>
<#=code.Escape(dependentProperty)#> = <#=code.Escape(navProperty)#>.<#=code.Escape(ef.GetCorrespondingPrincipalProperty(navProperty, dependentProperty))#>;
<#
}
#>
}
<#
if (navProperty.GetDependentProperties().Where(p => ef.IsNullable(p)).Any())
{
#>
else if (!skipKeys)
{
<#
foreach (var dependentProperty in navProperty.GetDependentProperties().Where(p => ef.IsNullable(p)))
{
#>
<#=code.Escape(dependentProperty)#> = null;
<#
}
#>
}
<#
}
}
else if (IsForeignKeyOrIdentifyingRelationship(ef, navProperty))
{
#>
if (<#=code.Escape(navProperty)#> != null)
{
<#
foreach (var fromProperty in ef.GetPrincipalProperties(navProperty))
{
#>
<#=code.Escape(navProperty)#>.<#=code.Escape(ef.GetCorrespondingDependentProperty(navProperty, fromProperty))#> = <#=code.Escape(fromProperty)#>;
<#
}
#>
}
<#
}
}
#>
if (ChangeTracker.ChangeTrackingEnabled)
{
if (ChangeTracker.OriginalValues.ContainsKey("<#=navProperty.Name#>")
&& (ChangeTracker.OriginalValues["<#=navProperty.Name#>"] == <#=code.Escape(navProperty)#>))
{
ChangeTracker.OriginalValues.Remove("<#=navProperty.Name#>");
}
else
{
ChangeTracker.RecordOriginalValue("<#=navProperty.Name#>", previousValue);
<#
if (ef.IsPrincipalEndOfIdentifyingRelationship((AssociationEndMember)navProperty.FromEndMember))
{
#>
// 这是识别关联的主体端,因此在移除关系时必须删除依赖。
// 如果依赖的当前状态为“已添加”,则可以更改关系而不会导致删除依赖。
if (previousValue != null && previousValue.ChangeTracker.State != ObjectState.Added)
{
previousValue.MarkAsDeleted();
}
<#
}
else if (inverse == null && ef.IsPrincipalEndOfIdentifyingRelationship((AssociationEndMember)navProperty.ToEndMember))
{
#>
// 这是识别关联的依赖端,因此在移除关系时必须删除。
// 如果当前状态为“已添加”,则可以更改关系而不会导致删除依赖。
// 这是从依赖到主体的单向关系,因此依赖端
// 负责级联删除。在所有其他情况下,主体端会对此进行管理。
if (previousValue != null && ChangeTracker.State != ObjectState.Added)
{
this.MarkAsDeleted();
}
<#
}
#>
}
if (<#=code.Escape(navProperty)#> != null && !<#=code.Escape(navProperty)#>.ChangeTracker.ChangeTrackingEnabled)
{
<#=code.Escape(navProperty)#>.StartTracking();
}
<#
if (IsSaveReference(ef, navProperty))
{
#>
Fixup<#=navProperty.Name#>Keys();
<#
}
if (inverse == null &&
!IsForeignKeyOrIdentifyingRelationship(ef, navProperty) &&
navProperty.FromEndMember.RelationshipMultiplicity != RelationshipMultiplicity.Many &&
navProperty.ToEndMember.RelationshipMultiplicity != RelationshipMultiplicity.One)
{
#>
if (previousValue != null)
{
previousValue.<#=CreateFixupMethodName(navProperty.FromEndMember)#>(null, false);
}
if (<#=code.Escape(navProperty)#> != null)
{
<#=code.Escape(navProperty)#>.<#=CreateFixupMethodName(navProperty.FromEndMember)#>(this, false);
}
<#
}
#>
}
}
<#
if (IsSaveReference(ef, navProperty))
{
EntityType targetType = (EntityType)navProperty.TypeUsage.EdmType;
List<string> keyNames = targetType.KeyMembers.Select(x => x.Name).ToList();
#>
private void Fixup<#=navProperty.Name#>Keys()
{
<#
for(int k=0; k < keyNames.Count; k++)
{
#>
const string <#=CreateKeyNameVariable(code.Escape(keyNames[k]))#> = "<#=CreateReferenceValueLookupKey(navProperty, keyNames[k])#>";
<#
}
#>
if(ChangeTracker.ExtendedProperties.ContainsKey(<#=CreateKeyNameVariable(code.Escape(keyNames[0]))#>)<#=keyNames.Count > 1 ? " &&" : ")"#>
<#
for(int k=1; k < keyNames.Count; k++)
{
#>
ChangeTracker.ExtendedProperties.ContainsKey(<#=CreateKeyNameVariable(code.Escape(keyNames[k]))#>)<#=k < keyNames.Count - 1 ? " &&" : ")" #>
<#
}
#>
{
if(<#=code.Escape(navProperty)#> == null ||
<#
for(int k=0; k < keyNames.Count; k++)
{
string equality = ((PrimitiveType)targetType.KeyMembers[keyNames[k]].TypeUsage.EdmType).PrimitiveTypeKind == PrimitiveTypeKind.Binary ? "EqualityComparer.Binary" : String.Empty;
#>
!<#=equality#>Equals(ChangeTracker.ExtendedProperties[<#=CreateKeyNameVariable(code.Escape(keyNames[k]))#>], <#=code.Escape(navProperty)#>.<#=code.Escape(keyNames[k])#>)<#=k < keyNames.Count - 1 ? " ||" : ")" #>
<#
}
#>
{
<#
for(int k=0; k < keyNames.Count; k++)
{
#>
ChangeTracker.RecordOriginalValue(<#=CreateKeyNameVariable(code.Escape(keyNames[k]))#>, ChangeTracker.ExtendedProperties[<#=CreateKeyNameVariable(code.Escape(keyNames[k]))#>]);
<#
}
#>
}
<#
for(int k=0; k < keyNames.Count; k++)
{
#>
ChangeTracker.ExtendedProperties.Remove(<#=CreateKeyNameVariable(code.Escape(keyNames[k]))#>);
<#
}
#>
}
}
<#
}
}
}
foreach (NavigationProperty navProperty in entity.NavigationProperties.Where(np => np.DeclaringType == entity))
{
NavigationProperty inverse = ef.Inverse(navProperty);
if (inverse != null && !IsReadWriteAccessibleProperty(inverse))
{
inverse = null;
}
if (navProperty.ToEndMember.RelationshipMultiplicity == RelationshipMultiplicity.Many)
{
#>
private void Fixup<#=navProperty.Name#>(object sender, NotifyCollectionChangedEventArgs e)
{
if (IsDeserializing)
{
return;
}
if (e.NewItems != null)
{
foreach (<#=code.Escape(navProperty.ToEndMember.GetEntityType())#> item in e.NewItems)
{
<#
if (inverse != null)
{
if (inverse.ToEndMember.RelationshipMultiplicity != RelationshipMultiplicity.Many)
{
#>
item.<#=code.Escape(inverse)#> = this;
<#
}
else
{
#>
if (!item.<#=code.Escape(inverse)#>.Contains(this))
{
item.<#=code.Escape(inverse)#>.Add(this);
}
<#
}
}
else if (IsForeignKeyOrIdentifyingRelationship(ef, navProperty))
{
foreach (var fromProperty in ef.GetPrincipalProperties(navProperty))
{
#>
item.<#=code.Escape(ef.GetCorrespondingDependentProperty(navProperty, fromProperty))#> = <#=code.Escape(fromProperty)#>;
<#
}
}
else if (navProperty.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne)
{
#>
item.<#=CreateFixupMethodName(navProperty.FromEndMember)#>(this, false);
<#
}
#>
if (ChangeTracker.ChangeTrackingEnabled)
{
if (!item.ChangeTracker.ChangeTrackingEnabled)
{
item.StartTracking();
}
ChangeTracker.RecordAdditionToCollectionProperties("<#=code.Escape(navProperty)#>", item);
}
<#
if (ef.IsCascadeDeletePrincipal(navProperty))
{
#>
// 这是执行级联删除的关联中的主体端。
// 更新事件侦听器以引用新依赖。
ChangeTracker.ObjectStateChanging += item.HandleCascadeDelete;
<#
}
#>
}
}
if (e.OldItems != null)
{
foreach (<#=code.Escape(navProperty.ToEndMember.GetEntityType())#> item in e.OldItems)
{
<#
if (inverse != null)
{
if (inverse.ToEndMember.RelationshipMultiplicity != RelationshipMultiplicity.Many)
{
#>
if (ReferenceEquals(item.<#=code.Escape(inverse)#>, this))
{
item.<#=code.Escape(inverse)#> = null;
}
<#
}
else
{
#>
if (item.<#=code.Escape(inverse)#>.Contains(this))
{
item.<#=code.Escape(inverse)#>.Remove(this);
}
<#
}
}
else if (IsForeignKeyOrIdentifyingRelationship(ef, navProperty))
{
foreach (var fromProperty in ef.GetPrincipalProperties(navProperty))
{
var p = ef.GetCorrespondingDependentProperty(navProperty, fromProperty);
if (ef.IsNullable(p.TypeUsage))
{
#>
item.<#=code.Escape(p)#> = null;
<#
}
}
}
else if (navProperty.FromEndMember.RelationshipMultiplicity == RelationshipMultiplicity.ZeroOrOne)
{
#>
item.<#=CreateFixupMethodName(navProperty.FromEndMember)#>(null, false);
<#
}
#>
if (ChangeTracker.ChangeTrackingEnabled)
{
ChangeTracker.RecordRemovalFromCollectionProperties("<#=code.Escape(navProperty)#>", item);
<#
if (ef.IsPrincipalEndOfIdentifyingRelationship((AssociationEndMember)navProperty.FromEndMember))
{
#>
// 删除此识别关联的依赖端。如果当前状态为“已添加”,
// 则允许更改关系而不会导致删除依赖。
if (item.ChangeTracker.State != ObjectState.Added)
{
item.MarkAsDeleted();
}
<#
}
#>
}
<#
if (ef.IsCascadeDeletePrincipal(navProperty))
{
#>
// 这是执行级联删除的关联中的主体端。
// 从事件侦听器中移除前一个依赖。
ChangeTracker.ObjectStateChanging -= item.HandleCascadeDelete;
<#
}
#>
}
}
}
<#
}
}
foreach(var associationEnd in shadowAssociationEnds)
{
AssociationType association = associationEnd.DeclaringType as AssociationType;
EntityType targetType = ((RefType)associationEnd.TypeUsage.EdmType).ElementType as EntityType;
List<string> keyNames = targetType.KeyMembers.Select(x => x.Name).ToList();
#>
internal void <#=CreateFixupMethodName(associationEnd)#>(<#=code.Escape(targetType)#> value, bool forceRemove)
{
<#
for(int k=0; k < keyNames.Count; k++)
{
#>
const string <#=CreateKeyNameVariable(code.Escape(keyNames[k]))#> = "<#=CreateReferenceValueLookupKey(associationEnd, keyNames[k])#>";
<#
}
#>
if (ChangeTracker.ChangeTrackingEnabled &&
<#
for(int k=0; k < keyNames.Count; k++)
{
#>
ChangeTracker.ExtendedProperties.ContainsKey(<#=CreateKeyNameVariable(code.Escape(keyNames[k]))#>)<#=k < keyNames.Count - 1 ? " &&" : ")"#>
<#
}
#>
{
if (forceRemove ||
<#
for(int k=0; k < keyNames.Count; k++)
{
string equality = ((PrimitiveType)targetType.KeyMembers[keyNames[k]].TypeUsage.EdmType).PrimitiveTypeKind == PrimitiveTypeKind.Binary ? "EqualityComparer.Binary" : String.Empty;
#>
!<#=equality#>Equals(ChangeTracker.ExtendedProperties[<#=CreateKeyNameVariable(code.Escape(keyNames[k]))#>], value == null ? null : (object)value.<#=code.Escape(keyNames[k])#>)<#=k < keyNames.Count - 1 ? " ||" : ")"#>
<#
}
#>
{
<#
for(int k=0; k < keyNames.Count; k++)
{
#>
ChangeTracker.RecordOriginalValue(<#=CreateKeyNameVariable(code.Escape(keyNames[k]))#>, ChangeTracker.ExtendedProperties[<#=CreateKeyNameVariable(code.Escape(keyNames[k]))#>]);
<#
}
#>
if (value == null)
{
<#
for(int k=0; k < keyNames.Count; k++)
{
#>
ChangeTracker.ExtendedProperties.Remove(<#=CreateKeyNameVariable(code.Escape(keyNames[k]))#>);
<#
}
#>
}
else
{
<#
for(int k=0; k < keyNames.Count; k++)
{
#>
ChangeTracker.ExtendedProperties[<#=CreateKeyNameVariable(code.Escape(keyNames[k]))#>] = value.<#=code.Escape(keyNames[k])#>;
<#
}
#>
}
}
}
}
<#
}
region.End();
#>
}
<#
EndNamespace(namespaceName);
}
foreach (ComplexType complex in ItemCollection.GetItems<ComplexType>().OrderBy(e => e.Name))
{
fileManager.StartNewFile(complex.Name + ".cs");
BeginNamespace(namespaceName, code);
#>
[Serializable]
<#=Accessibility.ForType(complex)#> partial class <#=code.Escape(complex)#> : INotifyComplexPropertyChanging, INotifyPropertyChanged
{
<#
region.Begin("基元属性");
foreach(EdmProperty edmProperty in complex.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == complex))
{
#>
[DataMember]
<#=Accessibility.ForProperty(edmProperty)#> <#=code.Escape(edmProperty.TypeUsage)#> <#=code.Escape(edmProperty)#>
{
<#=code.SpaceAfter(Accessibility.ForGetter(edmProperty))#>get { return <#=code.FieldName(edmProperty)#>; }
<#=code.SpaceAfter(Accessibility.ForSetter(edmProperty))#>set
{
if (<#=code.FieldName(edmProperty)#> != value)
{
OnComplexPropertyChanging();
<#=code.FieldName(edmProperty)#> = value;
OnPropertyChanged("<#=edmProperty.Name#>");
}
}
}
private <#=code.Escape(edmProperty.TypeUsage)#> <#=code.FieldName(edmProperty)#>;
<#
}
region.End();
region.Begin("复杂属性");
foreach(EdmProperty edmProperty in complex.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == complex))
{
#>
[DataMember]
<#=Accessibility.ForProperty(edmProperty)#> <#=code.Escape(edmProperty.TypeUsage)#> <#=code.Escape(edmProperty)#>
{
<#=code.SpaceAfter(Accessibility.ForGetter(edmProperty))#>get
{
if (!<#=InitializedTrackingField(edmProperty, code)#> && <#=code.FieldName(edmProperty)#> == null)
{
<#=code.FieldName(edmProperty)#> = new <#=code.Escape(edmProperty.TypeUsage)#>();
((INotifyComplexPropertyChanging)<#=code.FieldName(edmProperty)#>).ComplexPropertyChanging += HandleComplexPropertyChanging;
}
<#=InitializedTrackingField(edmProperty, code)#> = true;
return <#=code.FieldName(edmProperty)#>;
}
<#=code.SpaceAfter(Accessibility.ForSetter(edmProperty))#>set
{
<#=InitializedTrackingField(edmProperty, code)#> = true;
if (!Equals(<#=code.FieldName(edmProperty)#>, value))
{
if (<#=code.FieldName(edmProperty)#> != null)
{
((INotifyComplexPropertyChanging)<#=code.FieldName(edmProperty)#>).ComplexPropertyChanging -= HandleComplexPropertyChanging;
}
OnComplexPropertyChanging();
<#=code.FieldName(edmProperty)#> = value;
OnPropertyChanged("<#=edmProperty.Name#>");
if (value != null)
{
((INotifyComplexPropertyChanging)value).ComplexPropertyChanging += HandleComplexPropertyChanging;
}
}
}
}
private <#=code.Escape(edmProperty.TypeUsage)#> <#=code.FieldName(edmProperty)#>;
private bool <#=InitializedTrackingField(edmProperty, code)#>;
<#
}
region.End();
region.Begin("ChangeTracking");
#>
private void OnComplexPropertyChanging()
{
if (_complexPropertyChanging != null)
{
_complexPropertyChanging(this, new EventArgs());
}
}
event EventHandler INotifyComplexPropertyChanging.ComplexPropertyChanging { add { _complexPropertyChanging += value; } remove { _complexPropertyChanging -= value; } }
private event EventHandler _complexPropertyChanging;
private void OnPropertyChanged(String propertyName)
{
if (_propertyChanged != null)
{
_propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged { add { _propertyChanged += value; } remove { _propertyChanged -= value; } }
private event PropertyChangedEventHandler _propertyChanged;
<#
if(complex.Properties.Where(p => p.TypeUsage.EdmType is ComplexType && p.DeclaringType == complex).Count() > 0)
{
#>
private void HandleComplexPropertyChanging(object sender, EventArgs args)
{
// 生成事件气泡图并发送到所有侦听器,因为嵌套复杂属性中的某些内容已发生更改
OnComplexPropertyChanging();
}
<#
}
#>
public static void RecordComplexOriginalValues(String parentPropertyName, <#=code.Escape(complex)#> complexObject, ObjectChangeTracker changeTracker)
{
if (String.IsNullOrEmpty(parentPropertyName))
{
throw new ArgumentException("字符串参数不能为 null 或为空。", "parentPropertyName");
}
if (changeTracker == null)
{
throw new ArgumentNullException("changeTracker");
}
<#
foreach(EdmProperty complexProperty in complex.Properties)
{
if (complexProperty.TypeUsage.EdmType is ComplexType)
{
#>
<#=code.Escape(complexProperty.TypeUsage)#>.RecordComplexOriginalValues(String.Format(CultureInfo.InvariantCulture, "{0}.<#=complexProperty.Name#>", parentPropertyName), complexObject == null ? null : complexObject.<#=code.Escape(complexProperty)#>, changeTracker);
<#
}
else
{
#>
changeTracker.RecordOriginalValue(String.Format(CultureInfo.InvariantCulture, "{0}.<#=complexProperty.Name#>", parentPropertyName), complexObject == null ? null : (object)complexObject.<#=code.Escape(complexProperty)#>);
<#
}
}
#>
}
<#
region.End();
#>
}
<#
EndNamespace(namespaceName);
}
if (!VerifyTypesAreCaseInsensitiveUnique(ItemCollection))
{
return "";
}
fileManager.Process();
#>
<#+
void WriteHeader(EntityFrameworkTemplateFileManager fileManager, params string[] extraUsings)
{
fileManager.StartHeader();
#>
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码是根据模板生成的。
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,则所做更改将丢失。
// </auto-generated>
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.Serialization;
<#=String.Join(String.Empty, extraUsings.Select(u => "using " + u + ";" + Environment.NewLine).ToArray())#>
<#+
fileManager.EndBlock();
}
void BeginNamespace(string namespaceName, CodeGenerationTools code)
{
CodeRegion region = new CodeRegion(this);
if (!String.IsNullOrEmpty(namespaceName))
{
#>
namespace <#=code.EscapeNamespace(namespaceName)#>
{
<#+
PushIndent(CodeRegion.GetIndent(1));
}
}
void EndNamespace(string namespaceName)
{
if (!String.IsNullOrEmpty(namespaceName))
{
PopIndent();
#>
}
<#+
}
}
bool IsReadWriteAccessibleProperty(EdmMember member)
{
string setter = Accessibility.ForWriteOnlyProperty(member);
string getter = Accessibility.ForReadOnlyProperty(member);
return getter != "private" && getter != "protected" && setter != "private" && setter != "protected";
}
string InitializedTrackingField(EdmProperty property, CodeGenerationTools code)
{
string namePart = property.Name + "Initialized";
if (code.CamelCaseFields)
{
namePart = code.CamelCase(namePart);
}
return "_" + namePart;
}
void WriteEntityTypeSerializationInfo(EntityType type, ItemCollection itemCollection, CodeGenerationTools code, MetadataTools tools)
{
#>
[DataContract(IsReference = true)]
<#+
foreach(EntityType subtype in tools.GetSubtypesOf(type, itemCollection, true))
{
#>
[KnownType(typeof(<#=code.Escape(subtype)#>))]
<#+
}
List<EntityType> knownNavPropertyTypes = new List<EntityType>();
foreach(NavigationProperty navProperty in type.NavigationProperties.Where(np => np.DeclaringType == type))
{
EntityType navPropertyType = navProperty.ToEndMember.GetEntityType();
if(!knownNavPropertyTypes.Contains(navPropertyType))
{
knownNavPropertyTypes.Add(navPropertyType);
}
}
foreach(EntityType knownNavPropertyType in knownNavPropertyTypes)
{
#>
[KnownType(typeof(<#=code.Escape(knownNavPropertyType)#>))]
<#+
}
}
bool IsSaveReference(MetadataTools tools, NavigationProperty navProperty)
{
return !IsForeignKeyOrIdentifyingRelationship(tools, navProperty) &&
navProperty.ToEndMember.RelationshipMultiplicity != RelationshipMultiplicity.Many && // 目标为引用
navProperty.FromEndMember.RelationshipMultiplicity != RelationshipMultiplicity.One; // 源可以为 null (即,非 PK)
}
string CreateFixupMethodName(RelationshipEndMember endMember)
{
return String.Format(CultureInfo.InvariantCulture, "Fixup{0}_{1}_{2}Keys", endMember.DeclaringType.NamespaceName, endMember.DeclaringType.Name, endMember.Name);
}
string CreateKeyNameVariable(string keyName)
{
return String.Format(CultureInfo.InvariantCulture, "{0}KeyName", keyName);
}
string CreateReferenceValueLookupKey(AssociationEndMember endMember, string keyName)
{
return String.Format(CultureInfo.InvariantCulture, "Navigate({0}.{1}).{2}", endMember.DeclaringType.FullName, endMember.Name, keyName);
}
string CreateReferenceValueLookupKey(NavigationProperty navProp, string keyName)
{
return String.Format(CultureInfo.InvariantCulture, "{0}.{1}", navProp.Name, keyName);
}
void WriteCustomObservableCollection()
{
#>
// 在清除时引发各项删除通知
// 并防止添加重复项的 System.Collections.ObjectModel.ObservableCollection。
[Serializable]
public class TrackableCollection<T> : ObservableCollection<T>
{
protected override void ClearItems()
{
new List<T>(this).ForEach(t => Remove(t));
}
protected override void InsertItem(int index, T item)
{
if (!this.Contains(item))
{
base.InsertItem(index, item);
}
}
}
<#+
}
void WriteObjectChangeTracker()
{
#>
// 捕获需要针对自跟踪实体执行的大部分更改跟踪工作的
//帮助器类。
[DataContract(IsReference = true)]
[Serializable]
public class ObjectChangeTracker
{
#region Fields
private bool _isDeserializing;
private ObjectState _objectState = ObjectState.Added;
private bool _changeTrackingEnabled;
private OriginalValuesDictionary _originalValues;
private ExtendedPropertiesDictionary _extendedProperties;
private ObjectsAddedToCollectionProperties _objectsAddedToCollections = new ObjectsAddedToCollectionProperties();
private ObjectsRemovedFromCollectionProperties _objectsRemovedFromCollections = new ObjectsRemovedFromCollectionProperties();
#endregion
#region Events
public event EventHandler<ObjectStateChangingEventArgs> ObjectStateChanging;
#endregion
protected virtual void OnObjectStateChanging(ObjectState newState)
{
if (ObjectStateChanging != null)
{
ObjectStateChanging(this, new ObjectStateChangingEventArgs(){ NewState = newState });
}
}
[DataMember]
public ObjectState State
{
get { return _objectState; }
set
{
if (_isDeserializing || _changeTrackingEnabled)
{
OnObjectStateChanging(value);
_objectState = value;
}
}
}
public bool ChangeTrackingEnabled
{
get { return _changeTrackingEnabled; }
set { _changeTrackingEnabled = value; }
}
// 将已删除对象返回到已更改的集合值属性。
[DataMember]
public ObjectsRemovedFromCollectionProperties ObjectsRemovedFromCollectionProperties
{
get
{
if (_objectsRemovedFromCollections == null)
{
_objectsRemovedFromCollections = new ObjectsRemovedFromCollectionProperties();
}
return _objectsRemovedFromCollections;
}
}
// 返回已更改的属性的原始值。
[DataMember]
public OriginalValuesDictionary OriginalValues
{
get
{
if (_originalValues == null)
{
_originalValues = new OriginalValuesDictionary();
}
return _originalValues;
}
}
// 返回扩展属性值。
// 这包括实体框架中的并发模型所需的
// 独立关联的键值
[DataMember]
public ExtendedPropertiesDictionary ExtendedProperties
{
get
{
if (_extendedProperties == null)
{
_extendedProperties = new ExtendedPropertiesDictionary();
}
return _extendedProperties;
}
}
// 将已添加对象返回到已更改的集合值属性。
[DataMember]
public ObjectsAddedToCollectionProperties ObjectsAddedToCollectionProperties
{
get
{
if (_objectsAddedToCollections == null)
{
_objectsAddedToCollections = new ObjectsAddedToCollectionProperties();
}
return _objectsAddedToCollections;
}
}
#region MethodsForChangeTrackingOnClient
[OnDeserializing]
public void OnDeserializingMethod(StreamingContext context)
{
_isDeserializing = true;
}
[OnDeserialized]
public void OnDeserializedMethod(StreamingContext context)
{
_isDeserializing = false;
}
// 将 ObjectChangeTracker 重置为 Unchanged 状态,并
// 清除原始值和
// 集合属性的更改记录
public void AcceptChanges()
{
OnObjectStateChanging(ObjectState.Unchanged);
OriginalValues.Clear();
ObjectsAddedToCollectionProperties.Clear();
ObjectsRemovedFromCollectionProperties.Clear();
ChangeTrackingEnabled = true;
_objectState = ObjectState.Unchanged;
}
// 捕获正在更改的属性的原始值。
internal void RecordOriginalValue(string propertyName, object value)
{
if (_changeTrackingEnabled && _objectState != ObjectState.Added)
{
if (!OriginalValues.ContainsKey(propertyName))
{
OriginalValues[propertyName] = value;
}
}
}
// 记录对 SelfTracking 实体的集合值属性的添加操作。
internal void RecordAdditionToCollectionProperties(string propertyName, object value)
{
if (_changeTrackingEnabled)
{
// 如果在删除实体后重新添加该实体,则不应当在此处执行任何操作
if (ObjectsRemovedFromCollectionProperties.ContainsKey(propertyName)
&& ObjectsRemovedFromCollectionProperties[propertyName].Contains(value))
{
ObjectsRemovedFromCollectionProperties[propertyName].Remove(value);
if (ObjectsRemovedFromCollectionProperties[propertyName].Count == 0)
{
ObjectsRemovedFromCollectionProperties.Remove(propertyName);
}
return;
}
if (!ObjectsAddedToCollectionProperties.ContainsKey(propertyName))
{
ObjectsAddedToCollectionProperties[propertyName] = new ObjectList();
ObjectsAddedToCollectionProperties[propertyName].Add(value);
}
else
{
ObjectsAddedToCollectionProperties[propertyName].Add(value);
}
}
}
// 记录对 SelfTracking 实体的集合值属性的删除操作。
internal void RecordRemovalFromCollectionProperties(string propertyName, object value)
{
if (_changeTrackingEnabled)
{
// 如果在添加实体后重新删除该实体,则不应当在此处执行任何操作
if (ObjectsAddedToCollectionProperties.ContainsKey(propertyName)
&& ObjectsAddedToCollectionProperties[propertyName].Contains(value))
{
ObjectsAddedToCollectionProperties[propertyName].Remove(value);
if (ObjectsAddedToCollectionProperties[propertyName].Count == 0)
{
ObjectsAddedToCollectionProperties.Remove(propertyName);
}
return;
}
if (!ObjectsRemovedFromCollectionProperties.ContainsKey(propertyName))
{
ObjectsRemovedFromCollectionProperties[propertyName] = new ObjectList();
ObjectsRemovedFromCollectionProperties[propertyName].Add(value);
}
else
{
if (!ObjectsRemovedFromCollectionProperties[propertyName].Contains(value))
{
ObjectsRemovedFromCollectionProperties[propertyName].Add(value);
}
}
}
}
#endregion
}
#region EnumForObjectState
[Flags]
public enum ObjectState
{
Unchanged = 0x1,
Added = 0x2,
Modified = 0x4,
Deleted = 0x8
}
#endregion
[CollectionDataContract (Name = "ObjectsAddedToCollectionProperties",
ItemName = "AddedObjectsForProperty", KeyName = "CollectionPropertyName", ValueName = "AddedObjects")]
[Serializable]
public class ObjectsAddedToCollectionProperties : Dictionary<string, ObjectList>
{
public ObjectsAddedToCollectionProperties() { }
protected ObjectsAddedToCollectionProperties(SerializationInfo info,
StreamingContext ctx)
: base(info, ctx)
{ }
}
[CollectionDataContract (Name = "ObjectsRemovedFromCollectionProperties",
ItemName = "DeletedObjectsForProperty", KeyName = "CollectionPropertyName",ValueName = "DeletedObjects")]
[Serializable]
public class ObjectsRemovedFromCollectionProperties : Dictionary<string,ObjectList>
{
public ObjectsRemovedFromCollectionProperties() { }
protected ObjectsRemovedFromCollectionProperties(SerializationInfo info,
StreamingContext ctx)
:base(info, ctx)
{ }
}
[CollectionDataContract(Name = "OriginalValuesDictionary",
ItemName = "OriginalValues", KeyName = "Name", ValueName = "OriginalValue")]
[Serializable]
public class OriginalValuesDictionary : Dictionary<string, Object>
{
public OriginalValuesDictionary() { }
protected OriginalValuesDictionary(SerializationInfo info,
StreamingContext ctx)
: base(info, ctx)
{ }
}
[CollectionDataContract(Name = "ExtendedPropertiesDictionary",
ItemName = "ExtendedProperties", KeyName = "Name", ValueName = "ExtendedProperty")]
[Serializable]
public class ExtendedPropertiesDictionary : Dictionary<string, Object>
{
public ExtendedPropertiesDictionary() { }
protected ExtendedPropertiesDictionary(SerializationInfo info,
StreamingContext ctx)
: base(info, ctx)
{ }
}
[CollectionDataContract(ItemName = "ObjectValue")]
[Serializable]
public class ObjectList : List<object> { }
<#+
}
void WriteINotifyComplexPropertyChanging()
{
#>
// 一个提供当复杂属性发生更改时所触发的事件的接口。
// 更改可以是使用新的复杂类型实例替换复杂属性,也可以是
// 更改复杂类型实例中的标量属性。
public interface INotifyComplexPropertyChanging
{
event EventHandler ComplexPropertyChanging;
}
<#+
}
void WriteIObjectWithChangeTracker()
{
#>
// 接口由 EF 将生成的自跟踪实体实现。
// 我们将提供一个将此接口转换为 EF 的所需接口的适配器。
// 该适配器将在服务器端运行。
public interface IObjectWithChangeTracker
{
//具有给定对象的子图的所有更改跟踪信息。
ObjectChangeTracker ChangeTracker { get; }
}
public class ObjectStateChangingEventArgs : EventArgs
{
public ObjectState NewState { get; set; }
}
public static class ObjectWithChangeTrackerExtensions
{
public static T MarkAsDeleted<T>(this T trackingItem) where T : IObjectWithChangeTracker
{
if (trackingItem == null)
{
throw new ArgumentNullException("trackingItem");
}
trackingItem.ChangeTracker.ChangeTrackingEnabled = true;
trackingItem.ChangeTracker.State = ObjectState.Deleted;
return trackingItem;
}
public static T MarkAsAdded<T>(this T trackingItem) where T : IObjectWithChangeTracker
{
if (trackingItem == null)
{
throw new ArgumentNullException("trackingItem");
}
trackingItem.ChangeTracker.ChangeTrackingEnabled = true;
trackingItem.ChangeTracker.State = ObjectState.Added;
return trackingItem;
}
public static T MarkAsModified<T>(this T trackingItem) where T : IObjectWithChangeTracker
{
if (trackingItem == null)
{
throw new ArgumentNullException("trackingItem");
}
trackingItem.ChangeTracker.ChangeTrackingEnabled = true;
trackingItem.ChangeTracker.State = ObjectState.Modified;
return trackingItem;
}
public static T MarkAsUnchanged<T>(this T trackingItem) where T : IObjectWithChangeTracker
{
if (trackingItem == null)
{
throw new ArgumentNullException("trackingItem");
}
trackingItem.ChangeTracker.ChangeTrackingEnabled = true;
trackingItem.ChangeTracker.State = ObjectState.Unchanged;
return trackingItem;
}
public static void StartTracking(this IObjectWithChangeTracker trackingItem)
{
if (trackingItem == null)
{
throw new ArgumentNullException("trackingItem");
}
trackingItem.ChangeTracker.ChangeTrackingEnabled = true;
}
public static void StopTracking(this IObjectWithChangeTracker trackingItem)
{
if (trackingItem == null)
{
throw new ArgumentNullException("trackingItem");
}
trackingItem.ChangeTracker.ChangeTrackingEnabled = false;
}
public static void AcceptChanges(this IObjectWithChangeTracker trackingItem)
{
if (trackingItem == null)
{
throw new ArgumentNullException("trackingItem");
}
trackingItem.ChangeTracker.AcceptChanges();
}
}
<#+
}
void WriteEqualityComparer()
{
#>
public static class EqualityComparer
{
// 用于确定两个字节数组即使是不同对象引用也具有相同值的帮助器方法
public static bool BinaryEquals(object binaryValue1, object binaryValue2)
{
if (Object.ReferenceEquals(binaryValue1, binaryValue2))
{
return true;
}
byte[] array1 = binaryValue1 as byte[];
byte[] array2 = binaryValue2 as byte[];
if (array1 != null && array2 != null)
{
if (array1.Length != array2.Length)
{
return false;
}
for (int i = 0; i < array1.Length; i++)
{
if (array1[i] != array2[i])
{
return false;
}
}
return true;
}
return false;
}
}
<#+
}
bool VerifyTypesAreCaseInsensitiveUnique(EdmItemCollection itemCollection)
{
Dictionary<string, bool> alreadySeen = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
foreach(StructuralType type in itemCollection.GetItems<StructuralType>())
{
if (!(type is EntityType || type is ComplexType))
{
continue;
}
if (alreadySeen.ContainsKey(type.FullName))
{
Error(String.Format(CultureInfo.CurrentCulture, "该模板不支持仅大小写不同的类型,不支持类型 {0}", type.FullName));
return false;
}
else
{
alreadySeen.Add(type.FullName, true);
}
}
return true;
}
// 如果指定的导航属性的关联是识别关系或外键关系,则为 True。
private bool IsForeignKeyOrIdentifyingRelationship(MetadataTools tools, NavigationProperty navProperty)
{
if (tools == null)
{
throw new ArgumentNullException("tools");
}
if (navProperty == null)
{
throw new ArgumentNullException("navProperty");
}
return IsForeignKeyOrIdentifyingRelationship(tools, (AssociationType)navProperty.RelationshipType);
}
// 如果指定的关联是识别关系或外键关系,则为 True。
private bool IsForeignKeyOrIdentifyingRelationship(MetadataTools tools, AssociationType association)
{
if (tools == null)
{
throw new ArgumentNullException("tools");
}
if (association == null)
{
throw new ArgumentNullException("association");
}
return association.IsForeignKey || tools.IsIdentifyingRelationship(association);
}
// 在 OriginalValueMembers 构造函数中将 recordRequiredOriginalValuesOnly 设置为 false,以便始终记录所有原始值
public class OriginalValueMembers
{
private readonly HashSet<EdmProperty> _concurrencyMembers;
public OriginalValueMembers(bool recordRequiredOriginalValuesOnly, MetadataWorkspace metadataWorkspace, MetadataTools metadataTools)
{
if (recordRequiredOriginalValuesOnly)
{
try
{
_concurrencyMembers = new HashSet<EdmProperty>();
foreach (EntityContainer container in metadataWorkspace.GetItems<EntityContainer>(DataSpace.CSpace))
{
ILookup<EntityType, EntityType> directSubTypeLookup = metadataWorkspace.GetItems<EntityType>(DataSpace.CSpace).ToLookup(e => (EntityType)e.BaseType);
foreach (EntitySetBase eSet in container.BaseEntitySets.Where(es => es.BuiltInTypeKind == BuiltInTypeKind.EntitySet))
{
List<EntityType> subTypes = new List<EntityType>();
GetSubtypes(directSubTypeLookup, (EntityType)eSet.ElementType, subTypes);
foreach (EntityType eType in subTypes)
{
foreach (EdmProperty member in metadataWorkspace.GetRequiredOriginalValueMembers(eSet, eType))
{
_concurrencyMembers.Add(member);
}
}
}
}
// GetRequiredOriginalValueMembers 不会总是返回外键属性,但是这些属性是必需的
foreach (AssociationType assoc in metadataWorkspace.GetItems<AssociationType>(DataSpace.CSpace).Where(a => a.IsForeignKey))
{
foreach (EdmProperty toProperty in assoc.ReferentialConstraints[0].ToProperties)
{
_concurrencyMembers.Add(toProperty);
}
}
}
catch (Exception)
{
// 如果发生任何异常,请使用始终记录所有属性的原始值
_concurrencyMembers = null;
}
}
}
public bool IsOriginalValueMember(EdmProperty edmProperty)
{
return _concurrencyMembers == null || _concurrencyMembers.Contains(edmProperty);
}
private static void GetSubtypes(ILookup<EntityType, EntityType> lookup, EntityType eType, List<EntityType> subTypes)
{
subTypes.Add(eType);
foreach (EntityType subType in lookup[eType])
{
GetSubtypes(lookup, subType, subTypes);
}
}
}
#>