Skip to content
Snippets Groups Projects
Commit 02900d8d authored by Marcel Nellesen's avatar Marcel Nellesen
Browse files

Merge branch 'Sprint/2020-03' into 'master'

Sprint/2020-03

See merge request coscine/cs/database!54
parents ee099be3 26b4940f
No related branches found
No related tags found
1 merge request!54Sprint/2020-03
Showing
with 7 additions and 5126 deletions
stages:
- test
- docs
- release
- releasetrigger
......@@ -19,15 +18,6 @@ cake:Test:
- master
- tags
docs:
stage: docs
script:
- .\publishDocs.ps1 $GITLAB_TOKEN
variables:
GIT_STRATEGY: clone
only:
- tags
cake:Release:
stage: release
script:
......
param(
$token
)
$remoteUrl = git config --get remote.origin.url
$remoteUrl = $remoteUrl.replace("git@", "")
$remoteUrl = $remoteUrl -replace "https(.*?)@",""
$remoteUrl = $remoteUrl.replace(":", "/")
$remoteUrl = $remoteUrl.replace(".git", ".wiki.git")
$temporaryFolderName = "publishDocsTempFolder"
git clone "https://gitlab-ci-token:$($token)@$($remoteUrl)" $temporaryFolderName
cd $temporaryFolderName
Remove-Item *
cp -r ../docs/* ./
git add .
git commit -m "Docs: Documentation Update"
git push
\ No newline at end of file
......@@ -35,6 +35,12 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Consul, Version=0.7.2.6, Culture=neutral, PublicKeyToken=20a6ad9a81df1d95, processorArchitecture=MSIL">
<HintPath>..\packages\Consul.0.7.2.6\lib\net45\Consul.dll</HintPath>
</Reference>
<Reference Include="Coscine.Configuration, Version=1.4.0.0, Culture=neutral, PublicKeyToken=ce3d7a32d7dc1e5a, processorArchitecture=MSIL">
<HintPath>..\packages\Coscine.Configuration.1.4.0\lib\net461\Coscine.Configuration.dll</HintPath>
</Reference>
<Reference Include="FluentMigrator, Version=3.1.3.0, Culture=neutral, PublicKeyToken=aacfc7de5acabf05, processorArchitecture=MSIL">
<HintPath>..\packages\FluentMigrator.3.1.3\lib\net461\FluentMigrator.dll</HintPath>
</Reference>
......@@ -65,6 +71,7 @@
</Reference>
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http.WebRequest" />
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.4.0\lib\netstandard2.0\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
......@@ -87,39 +94,16 @@
<Compile Include="TestCoscineDB.cs" />
</ItemGroup>
<ItemGroup>
<None Include="LinqToDB.Templates\DataAnnotations.ttinclude" />
<None Include="LinqToDB.Templates\DataModel.ttinclude" />
<None Include="LinqToDB.Templates\EditableObject.ttinclude" />
<None Include="LinqToDB.Templates\Humanizer.ttinclude" />
<None Include="LinqToDB.Templates\LinqToDB.SqlServer.SqlTypes.Tools.ttinclude" />
<None Include="LinqToDB.Templates\LinqToDB.SqlServer.Tools.ttinclude" />
<None Include="LinqToDB.Templates\LinqToDB.SqlServer.ttinclude" />
<None Include="LinqToDB.Templates\LinqToDB.Tools.ttinclude" />
<None Include="LinqToDB.Templates\LinqToDB.ttinclude" />
<None Include="LinqToDB.Templates\MultipleFiles.ttinclude" />
<None Include="LinqToDB.Templates\NotifyDataErrorInfo.ttinclude" />
<None Include="LinqToDB.Templates\NotifyPropertyChanged.ttinclude" />
<None Include="LinqToDB.Templates\ObsoleteAttributes.ttinclude" />
<None Include="LinqToDB.Templates\PluralizationService.ttinclude" />
<None Include="LinqToDB.Templates\T4Model.ttinclude" />
<None Include="LinqToDB.Templates\Validation.ttinclude" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<WCFMetadata Include="Connected Services\" />
</ItemGroup>
<ItemGroup>
<Content Include="LinqToDB.Templates\CopyMe.SqlServer.tt.txt" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Database\Database.csproj">
<Project>{a7369ea1-f9ab-49d2-bdb1-c3facd37bbd0}</Project>
<Name>Database</Name>
</ProjectReference>
<ProjectReference Include="..\Migrator\Migrator.csproj">
<Project>{a48a255e-d08a-4336-b481-266debfabde9}</Project>
<Name>Migrator</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
......
<#@ template language="C#" debug="True" hostSpecific="True" #>
<#@ output extension=".generated.cs" #>
<#@ include file="$(LinqToDBT4SqlServerTemplatesDirectory)LinqToDB.SqlServer.Tools.ttinclude" #>
<#@ include file="$(LinqToDBT4SqlServerTemplatesDirectory)PluralizationService.ttinclude" #>
<# //@ include file="$(ProjectDir)LinqToDB.Templates\LinqToDB.SqlServer.Tools.ttinclude" #>
<# //@ include file="$(ProjectDir)LinqToDB.Templates\PluralizationService.ttinclude" #>
<#
/*
1. Create new *.tt file (e.g. MyDatabase.tt) in a folder where you would like to generate your data model
and copy content from this file to it. For example:
MyProject
DataModels
MyDatabase.tt
2. Modify the connection settings below to connect to your database.
3. Add connection string to the web/app.config file:
<connectionStrings>
<add name="MyDatabase" providerName="System.Data.SqlClient"
connectionString="Data Source=.;Database=MyDatabase;User Id=User;Password=TestPassword;" />
</connectionStrings>
4. To access your database use the following code:
using (var db = new MyDatabaseDB())
{
var q =
from c in db.Customers
select c;
foreach (var c in q)
Console.WriteLine(c.ContactName);
}
5. See more at https://github.com/linq2db/t4models
If you need to use the Microsoft.SqlServer.Types namespace, install the Microsoft.SqlServer.Types nuget,
and replace the following include at the top of this file:
"$(ProjectDir)LinqToDB.Templates\LinqToDB.SqlServer.Tools.ttinclude"
with
"$(ProjectDir)LinqToDB.Templates\LinqToDB.SqlServer.SqlTypes.Tools.ttinclude"
*/
NamespaceName = "DataModels";
LoadSqlServerMetadata("MyServer", "MyDatabase", "User", "Password");
// LoadSqlServerMetadata(".", "MyDatabase"); // Integrated Security
// LoadSqlServerMetadata(string connectionString);
GenerateModel();
#>
<#
{
var beforeGenerateModel = BeforeGenerateModel;
BeforeGenerateModel = () =>
{
beforeGenerateModel();
DataAnnotationsImpl();
};
}
#>
<#+
void DataAnnotationsImpl()
{
foreach (Class cl in GetTreeNodes(Model).OfType<Class>())
{
foreach (var p in GetTreeNodes(cl).OfType<Property>())
{
if (p.DisplayName != null)
{
p.Attributes.Add(new Attribute("Display", "Name=" + ToStringLiteral(p.DisplayName)) { IsSeparated = true });
}
if (p.IsRequired)
{
var attr = new Attribute("Required") { IsSeparated = true };
if (p.IsRequiredMessage != null)
attr.Parameters.Add(string.Format("ErrorMessage=" + ToStringLiteral(p.IsRequiredMessage), p.DisplayName ?? p.Name));
p.Attributes.Add(attr);
}
if (p.StringLength > 0)
{
var attr = new Attribute("StringLength", p.StringLength.ToString()) { IsSeparated = true };
if (p.StringLengthMessage != null)
attr.Parameters.Add(string.Format("ErrorMessage=" + ToStringLiteral(p.StringLengthMessage), p.DisplayName ?? p.Name));
p.Attributes.Add(attr);
// p.Attributes.Add(
// new Attribute("StringLength",
// p.StringLength.ToString(),
// "ErrorMessage=" + ToStringLiteral(string.Format(
// "The {0} must be a string with a maximum length of {1}.",
// p.DisplayName ?? "field",
// p.StringLength)))
// {
// IsSeparated = true
// });
}
}
}
}
partial class Property
{
public string DisplayName;
public bool IsRequired;
public string IsRequiredMessage;
public int StringLength;
public string StringLengthMessage;
}
#>
This diff is collapsed.
<#
{
var beforeGenerateModel = BeforeGenerateModel;
BeforeGenerateModel = () =>
{
EditableObjectImpl();
beforeGenerateModel();
};
SetPropertyValueAction += (obj,prop,val) =>
{
if (prop == "IsEditable")
obj.IsEditable = (bool)val;
};
}
#>
<#+
void EditableObjectImpl()
{
foreach (Property prop in GetTreeNodes(Model).OfType<Property>().Where(p => p.IsEditable).ToList())
{
SetPropertyValue(prop, "IsNotifying", true);
List<IClassMember> parentMembers;
MemberGroup gr = null;
if (prop.Parent is Class)
{
var parent = (Class)prop.Parent;
parentMembers = parent.Members;
}
else
{
var parent = (MemberGroup)prop.Parent;
parentMembers = parent.Members;
parent.IsCompact = false;
}
var name = prop.Name.Trim();
var type = prop.BuildType().Trim();
if (gr == null)
{
gr = new MemberGroup
{
Region = name + " : " + type,
Members = { prop },
IsPropertyGroup = true,
};
var index = parentMembers.IndexOf(prop);
parentMembers.RemoveAt(index);
parentMembers.Insert (index, gr);
}
var originalField = new Field(() => type, "_original" + name)
{
AccessModifier = AccessModifier.Private,
InsertBlankLineAfter = false,
};
gr.Members.Insert(0, originalField);
var currentField = new Field(() => type, " _current" + name)
{
AccessModifier = AccessModifier.Private,
InsertBlankLineAfter = false,
};
if (prop.InitValue != null)
currentField.InitValue = prop.InitValue;
gr.Members.Insert(0, currentField);
prop.Name = " " + name;
prop.TypeBuilder = () => " " + type;
prop.IsAuto = false;
if (prop.HasGetter) prop.GetBodyBuilders.Add(() => new [] { "return " + currentField.Name.Trim() + ";" });
if (prop.HasSetter) prop.SetBodyBuilders.Add(() => new [] { currentField.Name.Trim() + " = value;" });
var ac = new Method (() => "void", "Accept" + name + "Changes", null, () => new[] { string.Format("_original{0} = _current{0};", name) });
var rc = new Method (() => "void", "Reject" + name + "Changes", null, () => new[] { string.Format("{0} = _original{0};", name) });
var id = new Property(() => "bool", "Is" + name + "Dirty")
.InitGetter(() => new [] { string.Format(prop.IsDirtyText, "_current" + name, "_original" + name) });
gr.Members.Add(new MemberGroup
{
Region = "EditableObject support",
Members = { ac, rc, id },
});
prop.Parent.SetTree();
}
foreach (Class cl in GetTreeNodes(Model).OfType<Class>())
{
var props = GetTreeNodes(cl).OfType<Property>().Where(p => p.IsEditable).ToList();
if (props.Count > 0)
{
if (props.Any(p => p.IsEditable))
{
var ctor = GetTreeNodes(cl)
.OfType<Method>()
.FirstOrDefault(m => m.Name == cl.Name && m.ParameterBuilders.Count == 0);
if (ctor == null)
{
ctor = new Method(null, cl.Name);
cl.Members.Insert(0, ctor);
}
ctor.BodyBuilders.Add(() => new [] { "AcceptChanges();" });
}
var maxLen = props.Max(p => p.Name.Trim().Length);
var ac = new Method(() => "void", "AcceptChanges") { IsVirtual = true };
var rc = new Method(() => "void", "RejectChanges") { IsVirtual = true };
var id = new Property(() => "bool", "IsDirty") { IsAuto = false, HasSetter = false, IsVirtual = true };
ac.BodyBuilders.Add(() => new []
{
"BeforeAcceptChanges();",
""
});
rc.BodyBuilders.Add(() => new []
{
"BeforeRejectChanges();",
""
});
id.GetBodyBuilders.Add(() => new [] { "return" });
foreach (var p in props)
{
var name = p.Name.Trim();
ac.BodyBuilders.Add(() => new [] { string.Format("Accept{0}Changes();", name) });
rc.BodyBuilders.Add(() => new [] { string.Format("Reject{0}Changes();", name) });
id.GetBodyBuilders.Add(() => new [] { string.Format("\tIs{0}Dirty{1} ||", name, LenDiff(maxLen, name)) });
}
ac.BodyBuilders.Add(() => new[]
{
"",
"AfterAcceptChanges();"
});
rc.BodyBuilders.Add(() => new[]
{
"",
"AfterRejectChanges();"
});
var getBody = id.BuildGetBody().ToArray();
getBody[getBody.Length - 1] = getBody[getBody.Length - 1].Trim(' ' , '|') + ";";
id.GetBodyBuilders.Clear();
id.GetBodyBuilders.Add(() => getBody);
cl.Members.Add(new MemberGroup
{
Region = "EditableObject support",
Members =
{
new MemberGroup
{
IsCompact = true,
Members =
{
new Method(() => "void", "BeforeAcceptChanges") { AccessModifier = AccessModifier.Partial },
new Method(() => "void", "AfterAcceptChanges") { AccessModifier = AccessModifier.Partial },
}
},
ac,
new MemberGroup
{
IsCompact = true,
Members =
{
new Method(() => "void", "BeforeRejectChanges") { AccessModifier = AccessModifier.Partial },
new Method(() => "void", "AfterRejectChanges") { AccessModifier = AccessModifier.Partial },
}
},
rc,
id
},
});
if (!cl.Interfaces.Contains("IEditableObject"))
{
if (!Model.Usings.Contains("System.ComponentModel"))
Model.Usings.Add("System.ComponentModel");
cl.Interfaces.Add("IEditableObject");
cl.Members.Add(new MemberGroup
{
Region = "IEditableObject support",
Members =
{
new MemberGroup
{
IsCompact = true,
Members =
{
new Field (() => "bool", "_isEditing") { AccessModifier = AccessModifier.Private },
new Property(() => "bool", " IsEditing").InitGetter(() => new [] { "_isEditing" }),
}
},
new MemberGroup
{
IsCompact = true,
Members =
{
new Method(() => "void", "BeginEdit", null, () => new[] { "AcceptChanges();", "_isEditing = true;" }) { IsVirtual = true },
new Method(() => "void", "CancelEdit", null, () => new[] { "_isEditing = false;", "RejectChanges();", }) { IsVirtual = true },
new Method(() => "void", "EndEdit", null, () => new[] { "_isEditing = false;", "AcceptChanges();", }) { IsVirtual = true },
}
},
}
});
}
}
cl.SetTree();
}
}
partial class Property
{
public bool IsEditable;
public string IsDirtyText = "{0} != {1}";
}
class EditableProperty : Property
{
public EditableProperty()
{
IsEditable = true;
}
public EditableProperty(string type, string name)
: base(() => type, name, null, null)
{
IsEditable = true;
}
}
#>
<#
/*
To use this extension you should:
1) Reference Humanizer NuGet package into your project
2) Include Humanizer.ttinclude
3) Reference assembly like <_#@ assembly name="$(SolutionDir)\packages\Humanizer.Core.2.2.0\lib\netstandard1.0\Humanizer.dll" #_>
*/
#>
<#@ import namespace="Humanizer" #>
<#
NormalizeNames = true;
ToPlural = s => s.Pluralize (inputIsKnownToBeSingular: false);
ToSingular = s => s.Singularize(inputIsKnownToBePlural: false);
ToValidName = (s, r) => s.Pascalize();
#>
<#@ assembly name="$(LinqToDBT4SqlServerToolsDirectory)Microsoft.SqlServer.Types.dll" #>
<#@ include file="LinqToDB.Tools.ttinclude" #>
<#@ include file="LinqToDB.SqlServer.SqlTypes.ttinclude" #>
<#@ include file="LinqToDB.Tools.ttinclude" #>
<#@ include file="LinqToDB.SqlServer.ttinclude" #>
<#@ include file="LinqToDB.ttinclude" #>
<#
{
GenerateProcedureDbType = p => p.DataType == "Structured" && p.SchemaType != null;
var afterGenerateLinqToDBModel = AfterGenerateLinqToDBModel;
AfterGenerateLinqToDBModel = () =>
{
afterGenerateLinqToDBModel();
DoGenerateSqlServerFreeText();
};
var buildColumnComparison = BuildColumnComparison;
BuildColumnComparison = (c, padding1, padding2, last) =>
{
if (c.BuildType() == "SqlHierarchyId")
return string.Format("\t(bool)(t.{0}{1} == {0}{3}){2}", c.MemberName, padding1, last ? ");" : " &&", last ? "" : padding2);
else
return buildColumnComparison(c, padding1, padding2, last);
};
}
#>
<#+
bool GenerateSqlServerFreeText = true; // Defines whether to generate extensions for Free Text search, or not
void DoGenerateSqlServerFreeText()
{
if (!GenerateSqlServerFreeText)
return;
Model.Usings.Add("System.Collections.Generic");
Model.Usings.Add("System.Linq.Expressions");
Model.Usings.Add("System.Reflection");
Model.Usings.Add("LinqToDB");
Model.Usings.Add("LinqToDB.DataProvider.SqlServer");
Model.Usings.Add("LinqToDB.Extensions");
DataContextObject.Members.Add(
new MemberGroup
{
Region = "FreeTextTable",
Members =
{
new Class("FreeTextKey",
new MemberGroup
{
IsCompact = true,
Members =
{
new Field(() => "T", "Key"),
new Field(() => "int", "Rank")
}
})
{
GenericArguments = { "T" },
IsPartial = false
},
new Field(() => "MethodInfo", "_freeTextTableMethod1")
{
AccessModifier = AccessModifier.Private,
IsStatic = true,
InitValue = "typeof(" + DataContextObject.Name + ").GetMethod(\"FreeTextTable\", new Type[] { typeof(string), typeof(string) })"
},
new Method(() => "ITable<FreeTextKey<TKey>>", "FreeTextTable",
new Func<string>[] { () => "string field", () => "string text" },
() => new[]
{
"return this.GetTable<FreeTextKey<TKey>>(",
" this,",
" _freeTextTableMethod1,",
" field,",
" text);",
})
{
GenericArguments = new List<string>() { "TTable", "TKey" },
Attributes = { new Attribute("FreeTextTableExpression") }
},
new Field(() => "MethodInfo", "_freeTextTableMethod2")
{
AccessModifier = AccessModifier.Private,
IsStatic = true,
InitValue = Environment.NewLine +
" typeof(" + DataContextObject.Name + ").GetMethods()" + Environment.NewLine +
" .Where(m => m.Name == \"FreeTextTable\" && m.IsGenericMethod && m.GetParameters().Length == 2)" + Environment.NewLine +
" .Where(m => m.GetParameters()[0].ParameterType.IsGenericTypeEx() && m.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(Expression<>))" + Environment.NewLine +
" .Where(m => m.GetParameters()[1].ParameterType == typeof(string))" + Environment.NewLine +
" .Single()"
},
new Method(() => "ITable<FreeTextKey<TKey>>", "FreeTextTable",
new Func<string>[] { () => "Expression<Func<TTable,string>> fieldSelector", () => "string text" },
() => new[]
{
"return this.GetTable<FreeTextKey<TKey>>(",
" this,",
" _freeTextTableMethod2,",
" fieldSelector,",
" text);",
})
{
GenericArguments = { "TTable", "TKey" },
Attributes = { new Attribute("FreeTextTableExpression") }
},
}
}
);
}
LinqToDB.Data.DataConnection GetSqlServerConnection(string connectionString)
{
return LinqToDB.DataProvider.SqlServer.SqlServerTools.CreateDataConnection(connectionString);
}
LinqToDB.Data.DataConnection GetSqlServerConnection(string server, string database)
{
return GetSqlServerConnection(string.Format("Data Source={0};Database={1};Integrated Security=SSPI", server, database));
}
LinqToDB.Data.DataConnection GetSqlServerConnection(string server, string database, string user, string password)
{
return GetSqlServerConnection(string.Format("Server={0};Database={1};User Id={2};Password={3};", server, database, user, password));
}
void LoadSqlServerMetadata(string connectionString)
{
using (var dataConnection = GetSqlServerConnection(connectionString))
LoadMetadata(dataConnection);
}
void LoadSqlServerMetadata(string server, string database)
{
using (var dataConnection = GetSqlServerConnection(server, database))
LoadMetadata(dataConnection);
}
void LoadSqlServerMetadata(string server, string database, string user, string password)
{
using (var dataConnection = GetSqlServerConnection(server, database, user, password))
LoadMetadata(dataConnection);
}
#>
<#@ assembly name="$(LinqToDBT4ToolsDirectory)linq2db.dll" #>
This diff is collapsed.
<#@ assembly name="System.Core" #>
<#@ assembly name="EnvDTE" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="EnvDTE" #>
<#+
DTE _dte;
DTE DTE => _dte ?? (_dte = (DTE)((IServiceProvider)Host).GetService(typeof(DTE)));
ProjectItem _templateProjectItem;
ProjectItem TemplateProjectItem => _templateProjectItem ?? (_templateProjectItem = DTE.Solution.FindProjectItem(Host.TemplateFile));
readonly Dictionary<string,int> _fileNames = new Dictionary<string,int>();
Func<string,string,bool> CompareContent = (s1,s2) => s1 == s2;
void SaveOutput(string fileName, int fileType = 1)
{
var dir = Path.GetDirectoryName(Host.TemplateFile);
var output = Path.Combine(dir, fileName);
var newContent = GenerationEnvironment.ToString();
var oldContent = File.Exists(output) ? File.ReadAllText(output) : "";
if (!CompareContent(newContent, oldContent))
{
if (DTE.SourceControl != null && DTE.SourceControl.IsItemUnderSCC(output) && !DTE.SourceControl.IsItemCheckedOut(output))
DTE.SourceControl.CheckOutItem(output);
File.WriteAllText(output, newContent);
}
GenerationEnvironment.Length = 0;
_fileNames.Add(output, fileType);
}
void SyncProject()
{
var keepFileNames = _fileNames.ToDictionary(f => f.Key);
var projectFiles = new Dictionary<string,ProjectItem>();
var templateFileName = TemplateProjectItem.FileNames[0];
var originalFilePrefix = Path.GetFileNameWithoutExtension(templateFileName) + ".";
foreach (ProjectItem projectItem in TemplateProjectItem.ProjectItems)
{
projectFiles.Add(projectItem.FileNames[0], projectItem);
}
foreach (var pair in projectFiles)
{
if (!keepFileNames.ContainsKey(pair.Key))
if (!(Path.GetFileNameWithoutExtension(pair.Key) + ".").StartsWith(originalFilePrefix))
//if (pair.Key != templateFileName)
pair.Value.Delete();
}
// Add missing files to the project.
//
foreach (var fileName in keepFileNames)
{
if (!projectFiles.ContainsKey(fileName.Value.Key))
if (File.Exists(fileName.Value.Key))
{
var newItem = TemplateProjectItem.ProjectItems.AddFromFile(fileName.Value.Key);
newItem.Properties.Item("BuildAction").Value = fileName.Value.Value;
}
}
}
#>
<#
{
var beforeGenerateModel = BeforeGenerateModel;
BeforeGenerateModel = () =>
{
beforeGenerateModel();
NotifyDataErrorInfoImpl();
};
}
#>
<#+
void NotifyDataErrorInfoImpl()
{
foreach (var prop in GetTreeNodes(Model).OfType<Property>().Where(p => p.CustomValidation).ToList())
{
ITree p = prop.Parent;
while (!(p is Class) && p != null)
p = p.Parent;
if (p != null)
{
var cl = (Class)p;
if (!cl.Interfaces.Contains("INotifyDataErrorInfo"))
{
if (!Model.Usings.Contains("System.ComponentModel")) Model.Usings.Add("System.ComponentModel");
if (!Model.Usings.Contains("System.Collections")) Model.Usings.Add("System.Collections");
if (!Model.Usings.Contains("System.Linq")) Model.Usings.Add("System.Linq");
cl.Interfaces.Add("INotifyDataErrorInfo");
cl.Members.Add(new MemberGroup
{
Region = "INotifyDataErrorInfo support",
Members =
{
new Event(() => "EventHandler<DataErrorsChangedEventArgs>", "ErrorsChanged")
{
IsVirtual = true,
Attributes = { new Attribute("field : NonSerialized") { Conditional = "!SILVERLIGHT" } }
},
new Field(() => "Dictionary<string,List<string>>", "_validationErrors")
{
InitValue = "new Dictionary<string,List<string>>()",
AccessModifier = AccessModifier.Private,
IsReadonly = true,
Attributes = { new Attribute("field : NonSerialized") { Conditional = "!SILVERLIGHT" } }
},
new Method(() => "void", "AddError",
new Func<string>[]
{
() => "string propertyName",
() => "string error"
},
() => new[]
{
"List<string> errors;",
"",
"if (!_validationErrors.TryGetValue(propertyName, out errors))",
"{",
"\t_validationErrors[propertyName] = new List<string> { error };",
"}",
"else if (!errors.Contains(error))",
"{",
"\terrors.Add(error);",
"}",
"else",
"\treturn;",
"",
"OnErrorsChanged(propertyName);",
})
{
AccessModifier = AccessModifier.Public
},
new Method(() => "void", "RemoveError",
new Func<string>[]
{
() => "string propertyName",
},
() => new[]
{
"List<string> errors;",
"",
"if (_validationErrors.TryGetValue(propertyName, out errors) && errors.Count > 0)",
"{",
"\t_validationErrors.Clear();",
"\tOnErrorsChanged(propertyName);",
"}",
})
{
AccessModifier = AccessModifier.Public
},
new Method(() => "void", "OnErrorsChanged",
new Func<string>[]
{
() => "string propertyName",
},
() => new[]
{
"if (ErrorsChanged != null)",
"{",
"\tif (System.Windows.Deployment.Current.Dispatcher.CheckAccess())",
"\t\tErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));",
"\telse",
"\t\tSystem.Windows.Deployment.Current.Dispatcher.BeginInvoke(",
"\t\t\t() => ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName)));",
"}",
})
{
AccessModifier = AccessModifier.Protected
},
new Method(() => "IEnumerable", "GetErrors",
new Func<string>[]
{
() => "string propertyName",
},
() => new[]
{
"List<string> errors;",
"return propertyName != null && _validationErrors.TryGetValue(propertyName, out errors) ? errors : null;",
})
{
AccessModifier = AccessModifier.Public
},
new Property(() => "bool", "HasErrors").InitGetter(() => new [] { "_validationErrors.Values.Any(e => e.Count > 0)" })
}
});
}
}
}
}
#>
<#
{
var beforeGenerateModel = BeforeGenerateModel;
BeforeGenerateModel = () =>
{
beforeGenerateModel();
NotifyPropertyChangedImpl();
};
SetPropertyValueAction += (obj,prop,val) =>
{
if (prop == "IsNotifying")
obj.IsNotifying = (bool)val;
};
}
#><#+
public bool ImplementNotifyPropertyChanging;
public bool SkipNotifyPropertyChangedImplementation = false;
void NotifyPropertyChangedImpl()
{
foreach (Property prop in GetTreeNodes(Model).OfType<Property>().Where(p => p.IsNotifying).ToList())
{
List<IClassMember> parentMembers;
MemberGroup gr = null;
if (prop.Parent is Class)
{
var parent = (Class)prop.Parent;
parentMembers = parent.Members;
}
else
{
var parent = (MemberGroup)prop.Parent;
parent.IsCompact = false;
parentMembers = parent.Members;
if (parent.IsPropertyGroup)
gr = parent;
}
var name = prop.Name.Trim();
var type = prop.BuildType().Trim();
if (gr == null)
{
gr = new MemberGroup
{
Region = name + " : " + type,
Members = { prop },
IsPropertyGroup = true,
};
var index = parentMembers.IndexOf(prop);
parentMembers.RemoveAt(index);
parentMembers.Insert (index, gr);
}
if (prop.IsAuto)
{
var field = new Field(() => type, "_" + ToCamelCase(name))
{
AccessModifier = AccessModifier.Private,
InsertBlankLineAfter = false,
};
if (prop.InitValue != null)
field.InitValue = prop.InitValue;
gr.Members.Insert(0, field);
prop.Name = " " + name;
prop.TypeBuilder = () => " " + type;
prop.IsAuto = false;
if (prop.HasGetter) prop.GetBodyBuilders.Add(() => new [] { "return " + field.Name + ";" });
if (prop.HasSetter) prop.SetBodyBuilders.Add(() => new [] { field.Name + " = value;" });
}
var methods = new MemberGroup
{
Region = "INotifyPropertyChanged support",
Members =
{
new Field(() => "const string", "NameOf" + name)
{
InitValue = ToStringLiteral(name),
AccessModifier = AccessModifier.Public,
},
new Field(() => "PropertyChangedEventArgs", "_" + ToCamelCase(name) + "ChangedEventArgs")
{
InitValue = "new PropertyChangedEventArgs(NameOf" + name + ")",
AccessModifier = AccessModifier.Private,
IsStatic = true,
IsReadonly = true,
},
new Method(() => "void", "On" + name + "Changed", null,
() => new[] { "OnPropertyChanged(_" + ToCamelCase(name) + "ChangedEventArgs);" })
{
AccessModifier = AccessModifier.Private
}
}
};
gr.Members.Add(methods);
if (prop.Dependents.Count == 0)
prop.Dependents.Add(name);
if (ImplementNotifyPropertyChanging)
{
gr.Members.Add(new MemberGroup
{
Region = "INotifyPropertyChanging support",
Members =
{
new Field(() => "PropertyChangingEventArgs", "_" + ToCamelCase(name) + "ChangingEventArgs")
{
InitValue = "new PropertyChangingEventArgs(NameOf" + name + ")",
AccessModifier = AccessModifier.Private,
IsStatic = true,
IsReadonly = true,
},
new Method(() => "void", "On" + name + "Changing", null,
() => new[] { "OnPropertyChanging(_" + ToCamelCase(name) + "ChangingEventArgs);" })
{
AccessModifier = AccessModifier.Private
}
}
});
}
if (prop.HasSetter)
{
var setBody = prop.BuildSetBody().Select(s => "\t" + s).ToArray();
prop.SetBodyBuilders.Clear();
prop.SetBodyBuilders.Add(() => setBody);
string getValue;
var getBody = prop.BuildGetBody().ToArray();
if (getBody.Length == 1 && getBody[0].StartsWith("return"))
{
getValue = getBody[0].Substring("return".Length).Trim(' ', '\t', ';');
}
else
{
getValue = name;
}
var insSpaces = setBody.Length > 1;
var n = 0;
prop.SetBodyBuilders.Insert(n++, () => new [] {"if (" + getValue + " != value)", "{" });
if (ImplementNotifyPropertyChanging)
{
foreach (var dp in prop.Dependents)
prop.SetBodyBuilders.Insert(n++, () => new [] { "\tOn" + dp + "Changing();" });
prop.SetBodyBuilders.Insert(n++, () => new [] { "" });
}
prop.SetBodyBuilders.Insert(n++, () => new [] { "\tBefore" + name + "Changed(value);" });
if (insSpaces)
{
prop.SetBodyBuilders.Insert(3, () => new [] { "" });
prop.SetBodyBuilders.Add(() => new [] { "" });
}
prop.SetBodyBuilders.Add(() => new [] { "\tAfter" + name + "Changed();" });
prop.SetBodyBuilders.Add(() => new [] { "" });
foreach (var dp in prop.Dependents)
prop.SetBodyBuilders.Add(() => new [] { "\tOn" + dp + "Changed();" });
prop.SetBodyBuilders.Add(() => new [] { "}" });
methods.Members.Insert(0, new MemberGroup
{
IsCompact = true,
Members =
{
new Method(() => "void", "Before" + name + "Changed", new Func<string>[] { () => type + " newValue" }) { AccessModifier = AccessModifier.Partial },
new Method(() => "void", "After" + name + "Changed") { AccessModifier = AccessModifier.Partial },
}
});
}
prop.Parent.SetTree();
ITree p = prop.Parent;
while (!(p is Class) && p != null)
p = p.Parent;
if (p != null)
{
var cl = (Class)p;
if (!SkipNotifyPropertyChangedImplementation && !cl.Interfaces.Contains("INotifyPropertyChanged"))
{
if (!Model.Usings.Contains("System.ComponentModel"))
Model.Usings.Add("System.ComponentModel");
cl.Interfaces.Add("INotifyPropertyChanged");
cl.Members.Add(new MemberGroup
{
Region = "INotifyPropertyChanged support",
Members =
{
new Event(() => "PropertyChangedEventHandler", "PropertyChanged")
{
IsVirtual = true,
Attributes = { new Attribute("field : NonSerialized") { Conditional = "!SILVERLIGHT" } }
},
new Method(() => "void", "OnPropertyChanged", new Func<string>[] { () => "string propertyName" }, () => OnPropertyChangedBody)
{
AccessModifier = AccessModifier.Protected
},
new Method(() => "void", "OnPropertyChanged", new Func<string>[] { () => "PropertyChangedEventArgs arg" }, () => OnPropertyChangedArgBody)
{
AccessModifier = AccessModifier.Protected
},
}
});
}
if (ImplementNotifyPropertyChanging && !cl.Interfaces.Contains("INotifyPropertyChanging"))
{
if (!Model.Usings.Contains("System.ComponentModel"))
Model.Usings.Add("System.ComponentModel");
cl.Interfaces.Add("INotifyPropertyChanging");
cl.Members.Add(new MemberGroup
{
Region = "INotifyPropertyChanging support",
Members =
{
new Event(() => "PropertyChangingEventHandler", "PropertyChanging")
{
IsVirtual = true,
Attributes = { new Attribute("field : NonSerialized") { Conditional = "!SILVERLIGHT" } }
},
new Method(() => "void", "OnPropertyChanging", new Func<string>[] { () => "string propertyName" }, () => OnPropertyChangingBody)
{
AccessModifier = AccessModifier.Protected
},
new Method(() => "void", "OnPropertyChanging", new Func<string>[] { () => "PropertyChangingEventArgs arg" }, () => OnPropertyChangingArgBody)
{
AccessModifier = AccessModifier.Protected
},
}
});
}
}
}
}
public string[] OnPropertyChangedBody = new[]
{
"var propertyChanged = PropertyChanged;",
"",
"if (propertyChanged != null)",
"{",
"#if SILVERLIGHT",
"\tif (System.Windows.Deployment.Current.Dispatcher.CheckAccess())",
"\t\tpropertyChanged(this, new PropertyChangedEventArgs(propertyName));",
"\telse",
"\t\tSystem.Windows.Deployment.Current.Dispatcher.BeginInvoke(",
"\t\t\t() =>",
"\t\t\t{",
"\t\t\t\tvar pc = PropertyChanged;",
"\t\t\t\tif (pc != null)",
"\t\t\t\t\tpc(this, new PropertyChangedEventArgs(propertyName));",
"\t\t\t});",
"#else",
"\tpropertyChanged(this, new PropertyChangedEventArgs(propertyName));",
"#endif",
"}",
};
public string[] OnPropertyChangedArgBody = new[]
{
"var propertyChanged = PropertyChanged;",
"",
"if (propertyChanged != null)",
"{",
"#if SILVERLIGHT",
"\tif (System.Windows.Deployment.Current.Dispatcher.CheckAccess())",
"\t\tpropertyChanged(this, arg);",
"\telse",
"\t\tSystem.Windows.Deployment.Current.Dispatcher.BeginInvoke(",
"\t\t\t() =>",
"\t\t\t{",
"\t\t\t\tvar pc = PropertyChanged;",
"\t\t\t\tif (pc != null)",
"\t\t\t\t\tpc(this, arg);",
"\t\t\t});",
"#else",
"\tpropertyChanged(this, arg);",
"#endif",
"}",
};
public string[] OnPropertyChangingBody = new[]
{
"var propertyChanging = PropertyChanging;",
"",
"if (propertyChanging != null)",
"{",
"#if SILVERLIGHT",
"\tif (System.Windows.Deployment.Current.Dispatcher.CheckAccess())",
"\t\tpropertyChanging(this, new PropertyChangingEventArgs(propertyName));",
"\telse",
"\t\tSystem.Windows.Deployment.Current.Dispatcher.BeginInvoke(",
"\t\t\t() =>",
"\t\t\t{",
"\t\t\t\tvar pc = PropertyChanging;",
"\t\t\t\tif (pc != null)",
"\t\t\t\t\tpc(this, new PropertyChangingEventArgs(propertyName));",
"\t\t\t});",
"#else",
"\tpropertyChanging(this, new PropertyChangingEventArgs(propertyName));",
"#endif",
"}",
};
public string[] OnPropertyChangingArgBody = new[]
{
"var propertyChanging = PropertyChanging;",
"",
"if (propertyChanging != null)",
"{",
"#if SILVERLIGHT",
"\tif (System.Windows.Deployment.Current.Dispatcher.CheckAccess())",
"\t\tpropertyChanging(this, arg);",
"\telse",
"\t\tSystem.Windows.Deployment.Current.Dispatcher.BeginInvoke(",
"\t\t\t() =>",
"\t\t\t{",
"\t\t\t\tvar pc = PropertyChanging;",
"\t\t\t\tif (pc != null)",
"\t\t\t\t\tpc(this, arg);",
"\t\t\t});",
"#else",
"\tpropertyChanging(this, arg);",
"#endif",
"}",
};
partial class Property
{
public bool IsNotifying;
public List<string> Dependents = new List<string>();
}
class NotifyingProperty : Property
{
public NotifyingProperty()
{
IsNotifying = true;
}
public NotifyingProperty(string type, string name, params string[] dependents)
: base(() => type, name, null, null)
{
IsNotifying = true;
if (dependents.Length == 0)
Dependents.Add(name);
else
Dependents.AddRange(dependents);
}
}
#>
<#
{
var beforeGenerateLinqToDBModel = BeforeGenerateLinqToDBModel;
var afterGenerateLinqToDBModel = AfterGenerateLinqToDBModel;
var obsoleteTables = new List<Tuple<string,string,string>>();
BeforeGenerateLinqToDBModel = () =>
{
beforeGenerateLinqToDBModel();
foreach (var table in Tables.Values)
{
var idx = table.Description.IndexOf("[Obsolete");
if (idx >= 0)
{
var idx2 = table.Description.IndexOf(']', idx);
if (idx2 > idx)
{
var text = table.Description.Substring(idx + 1, idx2 - idx - 1);
var attr = new Attribute(text);
var info = Tuple.Create(table.Schema, table.Name, text);
if (obsoleteTables.All(a => a != info))
obsoleteTables.Add(info);
table.Attributes.Add(attr);
table.Description = table.Description.Substring(0, idx) + table.Description.Substring(idx2 + 1);
}
}
foreach (var c in table.Columns.Values)
{
idx = c.Description.IndexOf("[Obsolete");
if (idx >= 0)
{
var idx2 = c.Description.IndexOf(']', idx);
if (idx2 > idx)
{
var attr = new Attribute(c.Description.Substring(idx + 1, idx2 - idx - 1));
c.Attributes.Add(attr);
c.Description = c.Description.Substring(0, idx) + c.Description.Substring(idx2 + 1);
}
}
}
}
};
AfterGenerateLinqToDBModel = () =>
{
foreach (var tableInfo in obsoleteTables)
{
var schema = tableInfo.Item1;
var name = tableInfo.Item2;
var text = tableInfo.Item3;
var obsoleteAttr = new Attribute(text);
foreach (var cm in GetTreeNodes(Model)
.OfType<MemberBase>()
.Where(t => t.BuildType() != null)
.Where(t => t.BuildType() == name || t.BuildType().Contains("<" + name + ">")))
{
// check schema
if (cm.Parent != null && cm.Parent.Parent != null)
{
var parent = cm.Parent.Parent;
if (parent is Table)
{
var table = (Table)parent;
if (schema == table.Schema)
if (cm.Attributes.All(a => a.Name != text))
cm.Attributes.Add(obsoleteAttr);
}
else if (parent is Class)
{
var cls = (Class)parent;
bool parentClassIncludesSchemaName = cls.Name.Equals(schema + "Schema", StringComparison.InvariantCultureIgnoreCase);
bool classIsForDefaultSchema = cls.Name == DataContextName;
bool isExtensionMethod = cls.Parent is Namespace || cls.Name == "TableExtensions";
if (classIsForDefaultSchema || parentClassIncludesSchemaName || isExtensionMethod)
if (cm.Attributes.All(a => a.Name != text))
cm.Attributes.Add(obsoleteAttr);
}
}
}
}
afterGenerateLinqToDBModel();
};
}
#>
<#@ assembly name="System.Data.Entity.Design" #>
<#@ import namespace="System.Data.Entity.Design.PluralizationServices" #>
<#
{
ToPlural = Pluralization.ToPlural;
ToSingular = Pluralization.ToSingular;
}
#>
<#+
static class Pluralization
{
public static string CultureInfo = "en";
static PluralizationService _service;
public static Dictionary<string,string> Dictionary = new Dictionary<string,string>
{
{ "access", "accesses" }, { "afterlife", "afterlives" }, { "alga", "algae" },
{ "alumna", "alumnae" }, { "alumnus", "alumni" }, { "analysis", "analyses" },
{ "antenna", "antennae" }, { "appendix", "appendices" }, { "axis", "axes" },
{ "bacillus", "bacilli" }, { "basis", "bases" }, { "Bedouin", "Bedouin" },
{ "cactus", "cacti" }, { "calf", "calves" }, { "cherub", "cherubim" },
{ "child", "children" }, { "cod", "cod" }, { "cookie", "cookies" },
{ "criterion", "criteria" }, { "curriculum", "curricula" }, { "data", "data" },
{ "deer", "deer" }, { "diagnosis", "diagnoses" }, { "die", "dice" },
{ "dormouse", "dormice" }, { "elf", "elves" }, { "elk", "elk" },
{ "erratum", "errata" }, { "esophagus", "esophagi" }, { "fauna", "faunae" },
{ "fish", "fish" }, { "flora", "florae" }, { "focus", "foci" },
{ "foot", "feet" }, { "formula", "formulae" }, { "fundus", "fundi" },
{ "fungus", "fungi" }, { "genie", "genii" }, { "genus", "genera" },
{ "goose", "geese" }, { "grouse", "grouse" }, { "hake", "hake" },
{ "half", "halves" }, { "headquarters", "headquarters" }, { "hippo", "hippos" },
{ "hippopotamus", "hippopotami" }, { "hoof", "hooves" }, { "housewife", "housewives" },
{ "hypothesis", "hypotheses" }, { "index", "indices" }, { "info", "info" },
{ "jackknife", "jackknives" },
{ "knife", "knives" }, { "labium", "labia" }, { "larva", "larvae" },
{ "leaf", "leaves" }, { "life", "lives" }, { "loaf", "loaves" },
{ "louse", "lice" }, { "magus", "magi" }, { "man", "men" },
{ "memorandum", "memoranda" }, { "midwife", "midwives" }, { "millennium", "millennia" },
{ "moose", "moose" }, { "mouse", "mice" }, { "nebula", "nebulae" },
{ "neurosis", "neuroses" }, { "nova", "novas" }, { "nucleus", "nuclei" },
{ "oesophagus", "oesophagi" }, { "offspring", "offspring" }, { "ovum", "ova" },
{ "ox", "oxen" }, { "papyrus", "papyri" }, { "passerby", "passersby" },
{ "penknife", "penknives" }, { "person", "people" }, { "phenomenon", "phenomena" },
{ "placenta", "placentae" }, { "pocketknife", "pocketknives" }, { "process", "processes" },
{ "pupa", "pupae" }, { "radius", "radii" }, { "reindeer", "reindeer" },
{ "retina", "retinae" }, { "rhinoceros", "rhinoceros" }, { "roe", "roe" },
{ "salmon", "salmon" }, { "scarf", "scarves" }, { "self", "selves" },
{ "seraph", "seraphim" }, { "series", "series" }, { "sheaf", "sheaves" },
{ "sheep", "sheep" }, { "shelf", "shelves" }, { "species", "species" },
{ "spectrum", "spectra" }, { "status", "status" }, { "stimulus", "stimuli" },
{ "stratum", "strata" }, { "supernova", "supernovas" }, { "swine", "swine" },
{ "terminus", "termini" }, { "thesaurus", "thesauri" }, { "thesis", "theses" },
{ "thief", "thieves" }, { "trout", "trout" }, { "vulva", "vulvae" },
{ "wife", "wives" }, { "wildebeest", "wildebeest" }, { "wolf", "wolves" },
{ "woman", "women" }, { "yen", "yen" },
};
static string GetLastWord(string str)
{
if (string.IsNullOrWhiteSpace(str))
return string.Empty;
var i = str.Length - 1;
var isLower = char.IsLower(str[i]);
while (i > 0 && char.IsLetter(str[i - 1]) && char.IsLower(str[i - 1]) == isLower)
i--;
return str.Substring(isLower && i > 0 && char.IsLetter(str[i - 1]) ? i - 1 : i);
}
public static string ToPlural(string str)
{
if (_service == null)
_service = PluralizationService.CreateService(System.Globalization.CultureInfo.GetCultureInfo(CultureInfo));
var word = GetLastWord(str);
string newWord;
if (!Dictionary.TryGetValue(word.ToLower(), out newWord))
newWord = _service.IsPlural(word) ? word : _service.Pluralize(word);
if (string.Compare(word, newWord, true) != 0)
{
if (char.IsUpper(word[0]))
newWord = char.ToUpper(newWord[0]) + newWord.Substring(1, newWord.Length - 1).ToLower();
return word == str ? newWord : str.Substring(0, str.Length - word.Length) + newWord;
}
return str;
}
public static string ToSingular(string str)
{
if (_service == null)
_service = PluralizationService.CreateService(System.Globalization.CultureInfo.GetCultureInfo(CultureInfo));
var word = GetLastWord(str);
var newWord =
Dictionary
.Where(dic => string.Compare(dic.Value, word, true) == 0)
.Select(dic => dic.Key)
.FirstOrDefault()
??
(_service.IsSingular(word) ? word : _service.Singularize(word));
if (string.Compare(word, newWord, true) != 0)
{
if (char.IsUpper(word[0]))
newWord = char.ToUpper(newWord[0]) + newWord.Substring(1, newWord.Length - 1);
return word == str ? newWord : str.Substring(0, str.Length - word.Length) + newWord;
}
return str;
}
static string GetLastWordVersion1(string str)
{
if (string.IsNullOrWhiteSpace(str))
return string.Empty;
var i = str.Length - 1;
var isLower = char.IsLower(str[i]);
while (i > 0 && char.IsLower(str[i-1]) == isLower)
i--;
return str.Substring(isLower && i > 0 ? i - 1 : i);
}
public static string ToPluralVersion1(string str)
{
if (_service == null)
_service = PluralizationService.CreateService(System.Globalization.CultureInfo.GetCultureInfo(CultureInfo));
var word = GetLastWordVersion1(str);
string newWord;
if (!Dictionary.TryGetValue(word.ToLower(), out newWord))
newWord = _service.IsPlural(word) ? word : _service.Pluralize(word);
if (string.Compare(word, newWord, true) != 0)
{
if (char.IsUpper(word[0]))
newWord = char.ToUpper(newWord[0]) + newWord.Substring(1, newWord.Length - 1);
return word == str ? newWord : str.Substring(0, str.Length - word.Length) + newWord;
}
return str;
}
public static string ToSingularVersion1(string str)
{
if (_service == null)
_service = PluralizationService.CreateService(System.Globalization.CultureInfo.GetCultureInfo(CultureInfo));
var word = GetLastWordVersion1(str);
var newWord =
Dictionary
.Where(dic => string.Compare(dic.Value, word, true) == 0)
.Select(dic => dic.Key)
.FirstOrDefault()
??
(_service.IsSingular(word) ? word : _service.Singularize(word));
if (string.Compare(word, newWord, true) != 0)
{
if (char.IsUpper(word[0]))
newWord = char.ToUpper(newWord[0]) + newWord.Substring(1, newWord.Length - 1);
return word == str ? newWord : str.Substring(0, str.Length - word.Length) + newWord;
}
return str;
}
}
#>
This diff is collapsed.
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment