#@ template debug="false" hostspecific="false" language="C#" #>
//
// Copyright © CodeSmart Inc. All Rights Reserved.
//
<#@ include file="T4Toolbox.tt" #>
<#@ assembly name="EnvDTE" #>
<#@ import namespace="EnvDTE" #>
<#@ import namespace="System" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Diagnostics" #>
<#@ import namespace="System.Collections" #>
<#@ import namespace="System.Collections.Generic" #>
//** NOTE *****************************************************************
// This file was auto-generated by the CodeSmart Inc Entity-Framework T4
// template. You may modify the contents of this file... but it will be
// overwritten the next time Compilation of the project occurs or the *.TT
// template file is saved.
//*************************************************************************
<#+
private string _fileToRender;
public string FileToRender
{
get{return _fileToRender;}
set{_fileToRender = value;}
}
private EnvDTE.FileCodeModel _ttCodeModel;
public EnvDTE.FileCodeModel TTCodeModel {
get{return this._ttCodeModel;}
set{_ttCodeModel = value;}
}
private string _genericCollectionTypeName;
public string GenericCollectionTypeName
{
get{return _genericCollectionTypeName;}
set{ _genericCollectionTypeName = value;}
}
public EnvDTE.FileCodeModel GetCodeModel(string modelFileName)
{
if(this.TTCodeModel == null)
{
EnvDTE.ProjectItem dbmlProjectItem = T4Toolbox.TransformationContext.FindProjectItem(modelFileName);
EnvDTE.FileCodeModel codeModel = dbmlProjectItem.FileCodeModel;
if (codeModel == null)
{
throw new TransformationException(
string.Format(
"Unable to retrieve code model for '{0}'. Make sure it is being compiled by Visual Studio.",
modelFileName));
}
this.TTCodeModel = codeModel;
}
return this.TTCodeModel;
}
public void WriteDbmlISISExtensions()
{
WriteDbmlISISExtensions(this.FileToRender);
}
///
/// Returns object that represents the classes
/// defined in the file with the specified name.
///
public void WriteDbmlISISExtensions(string modelFileName)
{
if(GetCodeModel(modelFileName) != null)
{
#>
<#+
List nameSpaces = FindNamespaces(TTCodeModel.CodeElements);
if (nameSpaces == null || (nameSpaces != null && nameSpaces.Count <= 0))
{
throw new System.InvalidOperationException("Could not find a class declaration in " + modelFileName);
}
}
}
public List FindNamespaces(EnvDTE.CodeElements elements)
{
List output = new List();
foreach (EnvDTE.CodeElement element in elements)
{
EnvDTE.CodeNamespace codeThing = element as EnvDTE.CodeNamespace;
if (codeThing != null)
{
this.WriteLine("function " + codeThing.Name.Replace(".","_") + "Type() { }");
//this.WriteLine("var " + codeThing.Name + " = new " + codeThing.Name + "Type();");
this.WriteLine(string.Empty);
List classes = FindClasses(codeThing.Children, codeThing.Name);
this.WriteLine(string.Empty);
#>
<#+
output.Add(codeThing);
}
List result = FindNamespaces(element.Children);
if (result != null)
{
foreach (EnvDTE.CodeNamespace item in result)
{
output.Add(item);
}
//result.Any(i => {output.Add(i); return false;});
}
}
return output;
}
///
/// Traverses the specified collection of recursively and returns
/// the classes it finds.
///
public List FindClasses(EnvDTE.CodeElements elements, string parentNamespace)
{
List output = new List();
//First ... Build the list of NON-SPROC classes!
List nonSprocClasses = GetDataContextsProperties(elements);
//Second ... Build the actual DTO classes
foreach (EnvDTE.CodeElement element in elements)
{
EnvDTE.CodeClass codeThing = element as EnvDTE.CodeClass;
if (codeThing != null)
{
if(codeThing.Bases != null && codeThing.Bases.Count > 0)
{
CodeElement firstBase = null;
foreach (CodeElement item in codeThing.Bases)
{
firstBase = item;
break;
}
if(firstBase.Name != "ObjectContext")
{
if(CheckForNonSprocClass(nonSprocClasses, parentNamespace + "." + codeThing.Name))
{
this.PushIndent(" ");
this.WriteLine(string.Empty);
this.WriteLine("function " + codeThing.Name + "(originalJson) {"); //"DTO : BaseDataObject");
this.PushIndent(" ");
//this.WriteLine("this.prototype.constructor.call(originalJson);");
#>
this.changedProperties = {};
this.currentJsonEntity = {};
this.originalJsonEntity = {};
this.operationType = 0; //None
this.turnOnPropertyModified = function(propertyChanged) {
if(!this.changedProperties.hasOwnProperty(propertyChanged))
{
this.changedProperties[propertyChanged] = true;
if (this.changedProperties.length == null) { this.changedProperties.length = 0; }
this.changedProperties.length = this.changedProperties.length + 1;
}
}
if(originalJson == null) //If the caller explicitly passes NULL, then assume an 'Insert' operation and let it go.
return;
if(originalJson instanceof <#= codeThing.Name #>)
{
this.currentJsonEntity = originalJson.currentJsonEntity;
this.originalJsonEntity = originalJson.originalJsonEntity;
this.changedProperties = originalJson.changedProperties;
this.operationType = originalJson.operationType;
return;
}
if(!this.validateJsonMatchesType(originalJson))
{
throw "The application-support staff passed the wrong 'JSON' data to object '<#= codeThing.Name #>'.\n\nPlease alert your support team!";
return;
}
//Perform default load operation.
this.currentJsonEntity = $.parseJSON(JSON.stringify(originalJson));
this.originalJsonEntity = originalJson;
<#+
this.PopIndent();
this.WriteLine("}");
//this.WriteLine(string.Empty);
//this.WriteLine(codeThing.Name + ".prototype = BaseEntityTracker;");
//this.WriteLine(codeThing.Name + ".prototype.constructor = " + codeThing.Name + ";");
this.WriteLine(parentNamespace.Replace(".","_") + "Type." + codeThing.Name + " = " + codeThing.Name + ";");
this.WriteLine(codeThing.Name + ".TypeName = \"" + codeThing.Name + "\";");
this.PopIndent();
FindProperties(codeThing, parentNamespace, false);
this.WriteLine(string.Empty);
#>
<#= codeThing.Name #>.prototype.hasChanges = function() {
///
/// Checks the '<#= codeThing.Name #>' Javascript class's changed-properties array for any values.
/// If value.length > 0... then returns True.
/// Else returns False.
///
return this.changedProperties.length > 0;
}
<#= codeThing.Name #>.prototype.hasChanges_Complex = function(useSlowMethod) {
///
/// Checks the '<#= codeThing.Name #>' Javascript class's changed-properties array for
/// any values if 'FALSE' is passed in. Else, evaluates the actual current JSON fields
///against the original JSON fields to determine if there are differences!
/// Returns True if changes are found via either method.
/// Else returns False.
///
/// '_Complex' methods are intended to support JQuery-Template data-binding approaches.
///
if(useSlowMethod) {
var props = this.getChildByValueProperties();
for(var index in props)
{
var key = props[index];
if(this.currentJsonEntity[key] != this.originalJsonEntity[key])
this.turnOnPropertyModified(key);
}
}
return this.hasChanges();
}
<#= codeThing.Name #>.prototype.approveChanges = function() {
///
/// Loops through the 'changedProperties' array
/// and sets the appropriate 'originalJsonEntity' field
/// with the related 'currentJsonEntity' field.
/// Sets the operation-type to zero. (None)
/// Resets the changed-properties array.
///
for(var i in this.changedProperties)
{
this.originalJsonEntity[i] = this.currentJsonEntity[i];
}
this.operationType = 0; //None!
this.changedProperties = {};
return this;
}
<#= codeThing.Name #>.prototype.getTypeName = function() {
///
/// Returns the class-name of this '<#= codeThing.Name #>' Javascript class.
///
return <#= codeThing.Name #>.TypeName;
}
<#= codeThing.Name #>.prototype.setDeleteReady = function() {
///
/// Sets the '<#= codeThing.Name #>' operation-type to '4' for DELETE.
///
this.operationType = 4; //Delete!
}
<#= codeThing.Name #>.prototype.setOperationType = function() {
///
/// Checks the originalJsonEntity of the '<#= codeThing.Name #>' class for and fields. If any
/// exist, a check for 'hasChanges' is performed resulting in an 'Update' operation. (#3) If NO
/// fields exist, it is assumed that this is an 'Insert' operation. (#2) If the operation-type
/// is not already 'Delete' (#4), then an operation type of 'None' is assumed. (#0)
///
if(this.operationType != 4)
{
var foundAnyKeys = false;
for (var key in this.originalJsonEntity) {
if (this.originalJsonEntity.hasOwnProperty(key)) {
foundAnyKeys = true;
break;
}
}
if(!foundAnyKeys) {
this.operationType = 2; //Insert!
return;
}
if(this.hasChanges()) {
this.operationType = 3; //Update!
return;
}
}
}
<#= codeThing.Name #>.prototype.getChangeSet = function() {
///
/// Builds the JSON entity that .NET RIA Services expects during the 'SubmitChanges' AJAX method
/// call.
///
this.setOperationType();
if(this.operationType == 0)
return null;
//0 - none
//2 - insert
//3 - update
//4 - delete
var Operation = {};
Operation.Id = -1;
Operation.Operation = this.operationType;
Operation.OperationName = null;
Operation.OperationData = null;
Operation.Entity = {__type:"<#= codeThing.Name #>:#<#= parentNamespace #>"};
var mergedOutput = GlobalUtils.MergeJson(Operation.Entity, $.parseJSON(JSON.stringify(this.currentJsonEntity)));
Operation.Entity = mergedOutput;
if(this.operationType == 3) //If this is an update, then add original entity.
{
Operation.OriginalEntity = {__type:"<#= codeThing.Name #>:#<#= parentNamespace #>"};
mergedOutput = GlobalUtils.MergeJson(Operation.OriginalEntity, $.parseJSON(JSON.stringify(this.originalJsonEntity)));
Operation.OriginalEntity = mergedOutput;
}
//Operation.EntityActions = [{ "Key": "CustomUpdate", "Value": [true]} ];
return Operation;
//[{"ID":0,"Operation":2,"OperationName":null,"OperationData":null,"Entity":{"__type":"tTrack:#TrackService.Web","GeoY":37.422006,"RouteID":1,"DateTime":"/Date(1284609106567+1000)/","GeoX":-122.084095}}]};
}
<#+
output.Add(codeThing);
}
}
}
}
}
return output;
}
public List FindProperties(EnvDTE.CodeClass element, string parentNamespace, bool skipWritingOutput)
{
string className = element.Name;
List output = new List();
List primaryKeyPropertyNames = new List();
foreach (EnvDTE.CodeElement child in element.Children)
{
EnvDTE.CodeProperty codeThing = child as EnvDTE.CodeProperty;
if (codeThing != null)
{
foreach(EnvDTE.CodeAttribute attrib in codeThing.Attributes)
{
if(attrib.Value.Contains("EntityKeyProperty=true"))
{
if(primaryKeyPropertyNames.Count > 0)
primaryKeyPropertyNames[primaryKeyPropertyNames.Count - 1] += ",";
primaryKeyPropertyNames.Add("\"" + codeThing.Name + "\"");
}
}
output.Add(codeThing);
}
}
List byReferenceChildPropertyTypes = new List();
if(output != null && output.Count > 0)
{
List parentReferencePropertyNames = new List();
List referencePropertyNames = new List();
List byValuePropertyNames = new List();
this.PushIndent(" ");
this.Write(className + ".PrimaryKeyFieldNames = [{0}];", String.Concat(primaryKeyPropertyNames.ToArray()));
this.WriteLine(string.Empty);
this.WriteLine(string.Empty);
this.WriteLine(className + ".prototype.getPrimaryKeyFieldValues = function() { ");
this.PushIndent(" ");
this.WriteLine("/// Gets the values for the 1-or-more primary key(s) associated with this entity!");
this.Write("return [");
for(int z=0; z < primaryKeyPropertyNames.Count; z++)
this.Write("this.currentJsonEntity[" + className + ".PrimaryKeyFieldNames[" + z.ToString() + "]]" + GetArrayDelimiter(primaryKeyPropertyNames, primaryKeyPropertyNames[z]));
this.WriteLine("]; ");
this.PopIndent();
this.WriteLine("};");
this.WriteLine(string.Empty);
#>
<#= className #>.prototype.doesArrayMatchPrimaryKeyValues = function(arrayToCheck) {
///
/// Allows calling code to check whether the provided array is a match for the Primary-Key value
/// array associated with the entity.
///
if(!(arrayToCheck instanceof Array)) {
throw "The arrayToCheck parameter is not an Array!";
return;
}
var primaryKeyValues = this.getPrimaryKeyFieldValues();
for(var accessor in arrayToCheck) {
var arrayValue = arrayToCheck[accessor];
if(arrayValue != primaryKeyValues[accessor])
return false;
}
return true;
}
<#+
this.PopIndent();
this.WriteLine(string.Empty);
for(int i = 0; i","");
newTypeName = GenericCollectionTypeName + "<" + newTypeName.Substring(newTypeName.LastIndexOf(".") + 1) + ">";//"DTO>";
byReferenceChildPropertyTypes.Add(newTypeName);
referencePropertyNames.Add(item.Name);
}
else if (item.Type.AsString.Contains(parentNamespace)) //Item is a class in the same namespace as the source!
{
newTypeName = item.Type.AsString.Substring(item.Type.AsString.LastIndexOf(".") + 1); //+ "DTO";
parentReferencePropertyNames.Add(item.Name);
isParentReferenceProperty = true;
}
else
{
newTypeName = item.Type.AsString;
byValuePropertyNames.Add(item.Name);
}
if(!skipWritingOutput)
{
this.PushIndent(" ");
//this.WriteLine("public " + newTypeName + " " + item.Name);
#>
<#= className #>.<#= item.Name #>FieldName = "<#= item.Name #>";
<#= className #>.prototype.get<#= item.Name #> = function() {
///
/// Gets the '<#= className #>' class's CurrentJsonEntity's '<#= item.Name #>' field value.
///
return this.currentJsonEntity.<#= item.Name #>;
}
<#= className #>.prototype.set<#= item.Name #> = function(value) {
///
/// Sets the '<#= className #>' class's CurrentJsonEntity's '<#= item.Name #>' field value
/// and raises the 'OnPropertyModified' event notification internally.
///
this.turnOnPropertyModified(<#= className #>.<#= item.Name #>FieldName);
this.currentJsonEntity.<#= item.Name #> = value;
}
<#+
this.PopIndent();
}
}
if(!skipWritingOutput)
{
this.PushIndent(" ");
this.WriteLine(className + ".prototype.getParentReferenceProperties = function() {");
#>
///
/// Gets all of the parent entity-item fields associated with the '<#= className #>' class!
/// (Useful for the RIA services entity relationships.)
///
<#+
this.PushIndent(" ");
this.WriteLine("return [");
this.PushIndent(" ");
//Store the list of 'Parent-Reference Properties' in the class.
foreach(string parentRef in parentReferencePropertyNames)
this.WriteLine("\"" + parentRef + "\"" + GetArrayDelimiter(parentReferencePropertyNames, parentRef));
this.PopIndent();
this.WriteLine("];");
this.PopIndent();
this.WriteLine("}");
this.WriteLine(string.Empty);
this.WriteLine(className + ".prototype.getChildByValueProperties = function() {");
this.PushIndent(" ");
#>
///
/// Gets all of the main '<#= className #>' class fields! (Not the reference-type fields.)
///
<#+
this.WriteLine("return [");
this.PushIndent(" ");
//Store the list of 'Parent-Reference Properties' in the class.
foreach(string valName in byValuePropertyNames)
this.WriteLine("\"" + valName + "\"" + GetArrayDelimiter(byValuePropertyNames, valName));
this.PopIndent();
this.WriteLine("];");
this.PopIndent();
this.WriteLine("}");
this.WriteLine(string.Empty);
this.WriteLine(className + ".prototype.getChildByReferenceProperties = function() {");
this.PushIndent(" ");
#>
///
/// Gets the property names for the child-entity collections for the '<#= className #>' class!
/// (Useful for the RIA services entity relationships.)
///
<#+
this.WriteLine("return [");
this.PushIndent(" ");
//Store the list of 'Parent-Reference Properties' in the class.
foreach(string refName in referencePropertyNames)
this.WriteLine("\"" + refName + "\"" + GetArrayDelimiter(referencePropertyNames, refName));
this.PopIndent();
this.WriteLine("];");
this.PopIndent();
this.WriteLine("}");
this.WriteLine(string.Empty);
this.WriteLine(className + ".prototype.validateJsonMatchesType = function(jsonInput) {");
this.PushIndent(" ");
#>
///
/// Ensures that the fields necessary to support the RIA Service object for the '<#= className #>' class, actually exist in the JSON object provided!
///
<#+
foreach(string valName in byValuePropertyNames)
this.WriteLine("if(!jsonInput.hasOwnProperty(\"" + valName + "\")) return false;");
this.WriteLine("return true;");
this.PopIndent();
this.WriteLine("}");
this.WriteLine(string.Empty);
this.PopIndent();
} // end !skipWritingLines check...
}
//return output;
return byReferenceChildPropertyTypes;
}
private string GetArrayDelimiter(List stringCollectionToCheck, string currentItem)
{
return (stringCollectionToCheck != null &&
stringCollectionToCheck.Count >= 1 &&
currentItem != stringCollectionToCheck[stringCollectionToCheck.Count - 1] ?
", " : "");
}
private List GetDataContextsProperties(EnvDTE.CodeElements elements)
{
List nonSprocClasses = new List();
foreach (EnvDTE.CodeElement element in elements)
{
EnvDTE.CodeClass codeThing = element as EnvDTE.CodeClass;
if (codeThing != null)
{
if(codeThing.Bases != null && codeThing.Bases.Count > 0)
{
CodeElement firstBase = null;
foreach (CodeElement item in codeThing.Bases)
{
firstBase = item;
break;
}
if(firstBase.Name == "ObjectContext")
{
foreach (EnvDTE.CodeElement child in codeThing.Children)
{
EnvDTE.CodeProperty codeProperty = child as EnvDTE.CodeProperty;
if (codeProperty != null)
{
nonSprocClasses.Add(codeProperty);
}
}
}
}
}
}
return nonSprocClasses;
}
private bool CheckForNonSprocClass(List nonSprocClasses, string fullTypeName)
{
foreach(EnvDTE.CodeProperty prop in nonSprocClasses)
{
if(prop.Type.AsString.Replace("System.Data.Objects.ObjectSet<", "").Replace(">","") == fullTypeName)
{
return true;
}
}
return false;
}
#>