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