Entity Framework 5- Dynamically generating Enum from Values stored in Database - entity-framework

So, I have an existing lookup table in my database that stores an ID column(int), a description/Name for the ID Value. We have been using the data in this table for enumeration purposes.
We have since moved to using Entity Framework 5 and CodeFirst, but our lookup values are still in the database. What we would like to do is create an entity to represent the values, preferably an enum to access the values and names in that table and make them available for use in our application.
Normally, the code below would make sense for dynamically building an enumeration type from database values, but we want to get away from doing this.
static void GenerateStateEnumerations(String enumassemblyName, String enumTypeName, String assemblyName, IDictionary<int, String> EnumDB)
{
// Get the current application domain for the current thread.
AppDomain currentDomain = AppDomain.CurrentDomain;
// Create a dynamic assembly in the current application domain,
// and allow it to be executed and saved to disk.
AssemblyName EnumassemblyName = new AssemblyName(enumassemblyName);
AssemblyBuilder ab = currentDomain.DefineDynamicAssembly(
EnumassemblyName, AssemblyBuilderAccess.RunAndSave);
// Define a dynamic module in assemblyName assembly. For a single-
// module assembly, the module has the same name as the assembly.
ModuleBuilder mb = ab.DefineDynamicModule(EnumassemblyName.Name, EnumassemblyName.Name + ".dll");
// Define a public enumeration with the name "Elevation" and an
// underlying type of Integer.
EnumBuilder eb = mb.DefineEnum(enumTypeName, TypeAttributes.Public, typeof(int));
// Define the enumeration members
foreach (KeyValuePair<int, String> element in EnumDB)
{
eb.DefineLiteral(element.Value, element.Key);
}
// Create the type and save the assembly.
Type finished = eb.CreateType();
//Save the assembly via the assembly builder
ab.Save(EnumassemblyName.Name + ".dll");
}
How do I, in EF 5, create an entity that is an enumeration entity to represent the data stored in this table? Is this currently possible?

I know you said that you didn't want to do this dynamically, but have you looked at using text templates? If you use a text template (*.tt T4 file) The enum will be dynamically generated every time you do a build. Any new values in the table will be automatically added to the enum in the code.
Here's 1 example of how to create an enum from a text template:
<## template language="C#" hostSpecific="true" #>
<## output extension=".generated.cs" #>
<## Assembly Name="C:\Program Files (x86)\Common Files\microsoft shared\MSEnv\PublicAssemblies\EnvDTE.dll" #>
<## Assembly Name="System.Data" #>
<## assembly name="System.Configuration.dll" #>
<## Assembly Name="System.Core.dll" #>
<## import namespace="EnvDTE" #>
<## import namespace="System" #>
<## import namespace="System.Configuration" #>
<## import namespace="System.Data" #>
<## import namespace="System.Data.SqlClient" #>
<## import namespace="System.IO" #>
<## import namespace="System.Text.RegularExpressions" #>
<#
// This file dynamically creates Enumerations to be used in the [your project name] project.
// get an appSetting value
//string myAppSetting = AppSettings["myAppSetting"].Value;
// use a helper method to get value or default
// string absentAppSetting = (string)AppSettingValueOrDefault("xxx","default value for absent setting");
// get a project property
//string rootNamespace = Project.Properties.Item("RootNamespace").Value.ToString();
ConnectionStringSettings cs = ConnectionStrings["MyDBName"];
string tableName = "dbo.MyEnumTable"; // Path.GetFileNameWithoutExtension(Host.TemplateFile);
string path = Path.GetDirectoryName(Host.TemplateFile);
string columnId = "MyEnumTableId";
string columnName = "MyEnumTableValue";
string connectionString = cs.ConnectionString;
// Get containing project
IServiceProvider serviceProvider = (IServiceProvider)Host;
DTE dte = (DTE)serviceProvider.GetService(typeof(DTE));
Project project = dte.Solution.FindProjectItem(Host.TemplateFile).ContainingProject;
# > //remove space between # > issue with SO formatting
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
namespace <#= project.Properties.Item("DefaultNamespace").Value #>
{
/// <summary>
/// Auto generated enumeration from database table <#= tableName #>
/// </summary>
[GeneratedCode("TextTemplatingFileGenerator", "10")]
public enum MyEnumTableEnum
{
<#
SqlConnection conn = new SqlConnection(connectionString);
string command = string.Empty;
command = string.Format("select tbl.{0}, tbl.{1} from {2} as tbl order by tbl.{0}", columnId, columnName, tableName);
SqlCommand comm = new SqlCommand(command, conn);
conn.Open();
SqlDataReader reader = comm.ExecuteReader();
bool loop = reader.Read();
while(loop)
{
# > //remove space between # > issue with SO formatting
/// <summary>
/// <#= reader[columnName] #> configuration setting.
/// </summary>
<#= Pascalize(reader[columnName]) #> = <#= reader[columnId] #><# loop = reader.Read(); #><#= loop ? ",\r\n" : string.Empty #>
<#
}
#>
}
/// <summary>
/// This auto generated class is used to get or set the MyEnumTableEnum user friendly display names.
/// The 'values' object is of type Dictionary<int, string>
/// Usage: string keyValue = MyEnumTableDict.values[int key];
/// </summary>
public class MyEnumTableDict
{
public static Dictionary<int, string> values = new Dictionary<int, string>();
static MyEnumTableDict()
{
<#
reader.Close();
reader = comm.ExecuteReader();
loop = reader.Read();
while(loop)
{
#>
values[<#= reader[columnId] #>] = "<#= reader[columnName] #>";<#= "\r\n" #><# loop = reader.Read(); #>
<#
}
reader.Close();
reader.Dispose();
#>
}
}
}
<#+
/// <summary>
/// Used to Pascal-case objects
/// </summary>
private string Pascalize(object value)
{
Regex rx = new Regex(#"(?:[^a-zA-Z0-9]*)(?<first>[a-zA-Z0-9])(?<reminder>[a-zA-Z0-9]*)(?:[^a-zA-Z0-9]*)");
return rx.Replace(value.ToString(), m => m.Groups["first"].ToString().ToUpper() + m.Groups["reminder"].ToString().ToLower());
}
// Configuration Accessor Helpers
private static System.Configuration.Configuration _config;
private static EnvDTE.Project _project;
/// <summary>
/// Example:
/// <code>
/// string cs = ConnectionStrings["myConnectionString"].ConnectionString;
/// </code>
/// </summary>
private ConnectionStringSettingsCollection ConnectionStrings
{
get { return Configuration.ConnectionStrings.ConnectionStrings;}
}
/// <summary>
/// Example:
/// <code>
/// string setting = AppSettings["mySetting"].Value;
/// </code>
/// </summary>
private KeyValueConfigurationCollection AppSettings
{
get { return Configuration.AppSettings.Settings; }
}
/// <summary>
/// Returns value of setting, if present, otherwise defaultValue
/// </summary>
/// <param name="key">appSettings key</param>
/// <param name="defaultValue">value to return if setting is absent</param>
/// <returns></returns>
private object AppSettingValueOrDefault(string key,object defaultValue)
{
if (AppSettings[key] != null)
{
return AppSettings[key].Value;
}
return defaultValue;
}
/// <summary>
/// The app/web config file for hosting project, if any
/// </summary>
private System.Configuration.Configuration Configuration
{
get
{
if(_config==null)
{
string configurationFilename=null;
// examine each project item's filename looking for app.config or web.config
foreach (EnvDTE.ProjectItem item in Project.ProjectItems)
{
if (Regex.IsMatch(item.Name,"(app|web).config",RegexOptions.IgnoreCase))
{
// TODO: try this with linked files. is the filename pointing to the source?
configurationFilename=item.get_FileNames(0);
break;
}
}
if(!string.IsNullOrEmpty(configurationFilename))
{
// found it, map it and return it
ExeConfigurationFileMap configFile = null;
configFile = new ExeConfigurationFileMap();
configFile.ExeConfigFilename=configurationFilename;
_config = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(configFile, ConfigurationUserLevel.None);
}
}
return _config;
}
}
/// <summary>
/// The hosting project.
/// </summary>
private EnvDTE.Project Project
{
get
{
if(_project==null)
{
// Get the instance of Visual Studio that is hosting the calling file
EnvDTE.DTE env = (EnvDTE.DTE)((IServiceProvider)this.Host).GetService(typeof(EnvDTE.DTE));
// Gets an array of currently selected projects. Since you are either in this file saving it or
// right-clicking the item in solution explorer to invoke the context menu it stands to reason
// that there is 1 ActiveSolutionProject and that it is the parent of this file....
_project = (EnvDTE.Project)((Array)env.ActiveSolutionProjects).GetValue(0);
}
return _project;
}
}
#>
Update:
Forgot to include output class. Including now for completeness :)
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
namespace MyNameSpace
{
/// <summary>
/// Auto generated enumeration from database table dbo.MyEnumTable
/// </summary>
[GeneratedCode("TextTemplatingFileGenerator", "10")]
public enum MyEnumTableDictEnum
{
/// <summary>
/// description 1
/// </summary>
enumName1 = 1,
/// <summary>
/// description 2
/// </summary>
enumName2 = 2,
//..etc.
}
/// <summary>
/// This auto generated class is used to get or set the MyEnumTableDictEnum
/// user friendly display names.
/// The 'values' object is of type Dictionary<int, string>
/// Usage: string keyValue = MyEnumTableDict.values[int key];
/// </summary>
public class MyEnumTableDict
{
public static Dictionary<int, string> values = new Dictionary<int, string>();
static MyEnumTableDict()
{
values[1] = "EnumName1";
values[2] = "EnumName2";
values[3] = "...etc.";
}
}
}

Related

error CS0117: 'EditorUtility' does not contain a definition for 'RequestScriptReload'

In unity I keep on getting this error that keeps on bugging me, I tried to remove packages to leave one of these errors and it kept on going on and on, i am developing a game right now using unity engine and the errors are a big pain for me, this is the code that someone asked for, i dont really have much else to write other than this, stackoverlow isnt letting me just post it because its too short
using System;
using System.IO;
using UnityEngine;
namespace UnityEditor.SettingsManagement
{
/// <inheritdoc />
/// <summary>
/// A settings repository that stores data local to a Unity project.
/// </summary>
[Serializable]
public sealed class PackageSettingsRepository : ISettingsRepository
{
const string k_PackageSettingsDirectory = "ProjectSettings/Packages";
const bool k_PrettyPrintJson = true;
bool m_Initialized;
[SerializeField]
string m_Name;
[SerializeField]
string m_Path;
[SerializeField]
SettingsDictionary m_Dictionary = new SettingsDictionary();
/// <summary>
/// Constructor sets the serialized data path.
/// </summary>
/// <param name="package">
/// The package name.
/// </param>
/// <param name="name">
/// A name for this settings file. Settings are saved in `ProjectSettings/Packages/{package}/{name}.json`.
/// </param>
public PackageSettingsRepository(string package, string name)
{
m_Name = name;
m_Path = GetSettingsPath(package, name);
m_Initialized = false;
AssemblyReloadEvents.beforeAssemblyReload += Save;
EditorApplication.quitting += Save;
}
void Init()
{
if (m_Initialized)
return;
m_Initialized = true;
if (File.Exists(path))
{
m_Dictionary = null;
var json = File.ReadAllText(path);
EditorJsonUtility.FromJsonOverwrite(json, this);
if(m_Dictionary == null)
m_Dictionary = new SettingsDictionary();
}
}
/// <value>
/// This repository implementation is relevant to the Project scope.
/// </value>
/// <inheritdoc cref="ISettingsRepository.scope"/>
public SettingsScope scope
{
get { return SettingsScope.Project; }
}
/// <value>
/// The full path to the settings file.
/// This corresponds to `Unity Project/Project Settings/Packages/com.unity.package/name`.
/// </value>
/// <inheritdoc cref="ISettingsRepository.path"/>
public string path
{
get { return m_Path; }
}
/// <summary>
/// The name of this settings file.
/// </summary>
public string name
{
get { return m_Name; }
}
// Cannot call FindFromAssembly from a constructor or field initializer
// static string CreateSettingsPath(Assembly assembly, string name)
// {
// var info = PackageManager.PackageInfo.FindForAssembly(assembly);
// return string.Format("{0}/{1}/{2}.json", k_PackageSettingsDirectory, info.name, name);
// }
/// <summary>
/// Get a path for a settings file relative to the calling assembly package directory.
/// </summary>
/// <param name="packageName">The name of the package requesting this setting.</param>
/// <param name="name">An optional name for the settings file. Default is "Settings."</param>
/// <returns>A package-scoped path to the settings file within Project Settings.</returns>
public static string GetSettingsPath(string packageName, string name = "Settings")
{
return string.Format("{0}/{1}/{2}.json", k_PackageSettingsDirectory, packageName, name);
}
/// <summary>
/// Save all settings to their serialized state.
/// </summary>
/// <inheritdoc cref="ISettingsRepository.Save"/>
public void Save()
{
Init();
if (!File.Exists(path))
{
var directory = Path.GetDirectoryName(path);
Directory.CreateDirectory(directory);
}
#if UNITY_2019_3_OR_NEWER
if (!AssetDatabase.IsOpenForEdit(path))
{
if (!AssetDatabase.MakeEditable(path))
{
Debug.LogWarning($"Could not save package settings to {path}");
return;
}
}
#endif
try
{
File.WriteAllText(path, EditorJsonUtility.ToJson(this, k_PrettyPrintJson));
}
catch (UnauthorizedAccessException)
{
Debug.LogWarning($"Could not save package settings to {path}");
}
}
/// <summary>
/// Set a value for key of type T.
/// </summary>
/// <param name="key">The settings key.</param>
/// <param name="value">The value to set. Must be serializable.</param>
/// <typeparam name="T">Type of value.</typeparam>
/// <inheritdoc cref="ISettingsRepository.Set{T}"/>
public void Set<T>(string key, T value)
{
Init();
m_Dictionary.Set<T>(key, value);
}
/// <summary>
/// Get a value with key of type T, or return the fallback value if no matching key is found.
/// </summary>
/// <param name="key">The settings key.</param>
/// <param name="fallback">If no key with a value of type T is found, this value is returned.</param>
/// <typeparam name="T">Type of value to search for.</typeparam>
/// <inheritdoc cref="ISettingsRepository.Get{T}"/>
public T Get<T>(string key, T fallback = default(T))
{
Init();
return m_Dictionary.Get<T>(key, fallback);
}
/// <summary>
/// Does the repository contain a setting with key and type.
/// </summary>
/// <param name="key">The settings key.</param>
/// <typeparam name="T">The type of value to search for.</typeparam>
/// <returns>True if a setting matching both key and type is found, false if no entry is found.</returns>
/// <inheritdoc cref="ISettingsRepository.ContainsKey{T}"/>
public bool ContainsKey<T>(string key)
{
Init();
return m_Dictionary.ContainsKey<T>(key);
}
/// <summary>
/// Remove a key value pair from the settings repository.
/// </summary>
/// <param name="key"></param>
/// <typeparam name="T"></typeparam>
/// <inheritdoc cref="ISettingsRepository.Remove{T}"/>
public void Remove<T>(string key)
{
Init();
m_Dictionary.Remove<T>(key);
By the definition of 'RequestScriptReload' :
"The Unity Editor reloads script assemblies asynchronously on the next frame. This resets the state of all the scripts, but Unity does not compile any code that has changed since the previous compilation."
That means that your problem is probably with something that you changed.
You can try:
Going back to the last time everything wored and go on from there.
Closing all of you unity and scripting applications and opening it again.

OpenXML - Apply bookmarks to paragraph in word document

Below code works fine using OPENXML (asp.net) and print us elements in word document with HEADING2... how can we apply bookmark to specific paragraph..
What we r trying is extract sections between two HEADINGs...We are wondering how to apply bookmark and how can we use that extract text between two bookmarks...
const string fileName = #"D:\DocFiles\Scan.docx";
const string documentRelationshipType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument";
const string stylesRelationshipType = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
const string wordmlNamespace = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
XNamespace w = wordmlNamespace;
XDocument xDoc = null;
XDocument styleDoc = null;
using (Package wdPackage = Package.Open(fileName, FileMode.Open, FileAccess.Read))
{
PackageRelationship docPackageRelationship =
wdPackage
.GetRelationshipsByType(documentRelationshipType)
.FirstOrDefault();
if (docPackageRelationship != null)
{
Uri documentUri =
PackUriHelper
.ResolvePartUri(
new Uri("/", UriKind.Relative),
docPackageRelationship.TargetUri);
PackagePart documentPart =
wdPackage.GetPart(documentUri);
// Load the document XML in the part into an XDocument instance.
xDoc = XDocument.Load(XmlReader.Create(documentPart.GetStream()));
// Find the styles part. There will only be one.
PackageRelationship styleRelation =
documentPart.GetRelationshipsByType(stylesRelationshipType)
.FirstOrDefault();
if (styleRelation != null)
{
Uri styleUri = PackUriHelper.ResolvePartUri(documentUri, styleRelation.TargetUri);
PackagePart stylePart = wdPackage.GetPart(styleUri);
// Load the style XML in the part into an XDocument instance.
styleDoc = XDocument.Load(XmlReader.Create(stylePart.GetStream()));
}
}
}
string defaultStyle =
(string)(
from style in styleDoc.Root.Elements(w + "style")
where (string)style.Attribute(w + "type") == "paragraph" &&
(string)style.Attribute(w + "default") == "1"
select style
).First().Attribute(w + "styleId");
// Find all paragraphs in the document.
var paragraphs =
from para in xDoc
.Root
.Element(w + "body")
.Descendants(w + "p")
let styleNode = para
.Elements(w + "pPr")
.Elements(w + "pStyle")
.FirstOrDefault()
select new
{
ParagraphNode = para,
StyleName = styleNode != null ?
(string)styleNode.Attribute(w + "val") :
defaultStyle
};
// Retrieve the text of each paragraph.
var paraWithText =
from para in paragraphs
select new
{
ParagraphNode = para.ParagraphNode,
StyleName = para.StyleName,
Text = ParagraphText(para.ParagraphNode)
};
foreach (var p in paraWithText)
{
if (p.StyleName=="Heading2")
{
Response.Write(p.StyleName + " -" + p.Text);
Response.Write("</br>");
}
}
Here's a sample Bookmark class that I created to demonstrate how you can deal with bookmarks. It finds pairs of w:bookmarkStart and w:bookmarkEnd elements and shows how you can get hold of the w:r elements between those two markers. Based on that, you can process the text, e.g., as shown in the GetValue() method.
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using OpenXmlPowerTools;
namespace CodeSnippets.OpenXml.Wordprocessing
{
/// <summary>
/// Represents a corresponding pair of w:bookmarkStart and w:bookmarkEnd elements.
/// </summary>
public class Bookmark
{
private Bookmark(XElement root, string bookmarkName)
{
Root = root;
BookmarkStart = new XElement(W.bookmarkStart,
new XAttribute(W.id, -1),
new XAttribute(W.name, bookmarkName));
BookmarkEnd = new XElement(W.bookmarkEnd,
new XAttribute(W.id, -1));
}
private Bookmark(XElement root, XElement bookmarkStart, XElement bookmarkEnd)
{
Root = root;
BookmarkStart = bookmarkStart;
BookmarkEnd = bookmarkEnd;
}
/// <summary>
/// The root element containing both <see cref="BookmarkStart"/> and
/// <see cref="BookmarkEnd"/>.
/// </summary>
public XElement Root { get; }
/// <summary>
/// The w:bookmarkStart element.
/// </summary>
public XElement BookmarkStart { get; }
/// <summary>
/// The w:bookmarkEnd element.
/// </summary>
public XElement BookmarkEnd { get; }
/// <summary>
/// Finds a pair of w:bookmarkStart and w:bookmarkEnd elements in the given
/// <paramref name="root"/> element, where the w:name attribute value of the
/// w:bookmarkStart element is equal to <paramref name="bookmarkName"/>.
/// </summary>
/// <param name="root">The root <see cref="XElement"/>.</param>
/// <param name="bookmarkName">The bookmark name.</param>
/// <returns>A new <see cref="Bookmark"/> instance representing the bookmark.</returns>
public static Bookmark Find(XElement root, string bookmarkName)
{
XElement bookmarkStart = root
.Descendants(W.bookmarkStart)
.FirstOrDefault(e => (string) e.Attribute(W.name) == bookmarkName);
string id = bookmarkStart?.Attribute(W.id)?.Value;
if (id == null) return new Bookmark(root, bookmarkName);
XElement bookmarkEnd = root
.Descendants(W.bookmarkEnd)
.FirstOrDefault(e => (string) e.Attribute(W.id) == id);
return bookmarkEnd != null
? new Bookmark(root, bookmarkStart, bookmarkEnd)
: new Bookmark(root, bookmarkName);
}
/// <summary>
/// Gets all w:r elements between the bookmark's w:bookmarkStart and
/// w:bookmarkEnd elements.
/// </summary>
/// <returns>A collection of w:r elements.</returns>
public IEnumerable<XElement> GetRuns()
{
return Root
.Descendants()
.SkipWhile(d => d != BookmarkStart)
.Skip(1)
.TakeWhile(d => d != BookmarkEnd)
.Where(d => d.Name == W.r);
}
/// <summary>
/// Gets the concatenated inner text of all runs between the bookmark's
/// w:bookmarkStart and w:bookmarkEnd elements, ignoring paragraph marks
/// and page breaks.
/// </summary>
/// <remarks>
/// The output of this method can be compared to the output of the
/// <see cref="XElement.Value"/> property.
/// </remarks>
/// <returns>The concatenated inner text.</returns>
public string GetValue()
{
return GetRuns().Select(UnicodeMapper.RunToString).StringConcatenate();
}
}
}
The above class processes documents like the following (very simple test document):
<?xml version="1.0" encoding="utf-8"?>
<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
<w:body>
<w:p>
<w:r>
<w:t>First</w:t>
</w:r>
</w:p>
<w:bookmarkStart w:id="1" w:name="_Bm001" />
<w:p>
<w:r>
<w:t>Second</w:t>
</w:r>
</w:p>
<w:p>
<w:r>
<w:t>Third</w:t>
</w:r>
</w:p>
<w:bookmarkEnd w:id="1" />
<w:p>
<w:r>
<w:t>Fourth</w:t>
</w:r>
</w:p>
</w:body>
</w:document>
The above document is created by the following unit tests, which demonstrate how you could use the Bookmark class:
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using CodeSnippets.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using OpenXmlPowerTools;
using Xunit;
namespace CodeSnippets.Tests.OpenXml.Wordprocessing
{
public class BookmarkTests
{
/// <summary>
/// The w:name value of our bookmark.
/// </summary>
private const string BookmarkName = "_Bm001";
/// <summary>
/// The w:id value of our bookmark.
/// </summary>
private const int BookmarkId = 1;
/// <summary>
/// The test w:document with our bookmark, which encloses the two runs
/// with inner texts "Second" and "Third".
/// </summary>
private static readonly XElement Document =
new XElement(W.document,
new XAttribute(XNamespace.Xmlns + "w", W.w.NamespaceName),
new XElement(W.body,
new XElement(W.p,
new XElement(W.r,
new XElement(W.t, "First"))),
new XElement(W.bookmarkStart,
new XAttribute(W.id, BookmarkId),
new XAttribute(W.name, BookmarkName)),
new XElement(W.p,
new XElement(W.r,
new XElement(W.t, "Second"))),
new XElement(W.p,
new XElement(W.r,
new XElement(W.t, "Third"))),
new XElement(W.bookmarkEnd,
new XAttribute(W.id, BookmarkId)),
new XElement(W.p,
new XElement(W.r,
new XElement(W.t, "Fourth")))
)
);
/// <summary>
/// Creates a <see cref="WordprocessingDocument"/> for on a <see cref="MemoryStream"/>
/// testing purposes, using the given <paramref name="document"/> as the w:document
/// root element of the main document part.
/// </summary>
/// <param name="document">The w:document root element.</param>
/// <returns>The <see cref="MemoryStream"/> containing the <see cref="WordprocessingDocument"/>.</returns>
private static MemoryStream CreateWordprocessingDocument(XElement document)
{
var stream = new MemoryStream();
const WordprocessingDocumentType type = WordprocessingDocumentType.Document;
using (WordprocessingDocument wordDocument = WordprocessingDocument.Create(stream, type))
{
MainDocumentPart part = wordDocument.AddMainDocumentPart();
part.PutXDocument(new XDocument(document));
}
return stream;
}
[Fact]
public void GetRuns_WordprocessingDocumentWithBookmarks_CorrectRunsReturned()
{
// Arrange.
// Create a new Word document on a Stream, using the test w:document
// as the main document part.
Stream stream = CreateWordprocessingDocument(Document);
// Open the WordprocessingDocument on the Stream, using the Open XML SDK.
using WordprocessingDocument wordDocument = WordprocessingDocument.Open(stream, true);
// Get the w:document element from the main document part and find
// our bookmark.
XElement document = wordDocument.MainDocumentPart.GetXElement();
Bookmark bookmark = Bookmark.Find(document, BookmarkName);
// Act, getting the bookmarked runs.
IEnumerable<XElement> runs = bookmark.GetRuns();
// Assert.
Assert.Equal(new[] {"Second", "Third"}, runs.Select(run => run.Value));
}
[Fact]
public void GetText_WordprocessingDocumentWithBookmarks_CorrectRunsReturned()
{
// Arrange.
// Create a new Word document on a Stream, using the test w:document
// as the main document part.
Stream stream = CreateWordprocessingDocument(Document);
// Open the WordprocessingDocument on the Stream, using the Open XML SDK.
using WordprocessingDocument wordDocument = WordprocessingDocument.Open(stream, true);
// Get the w:document element from the main document part and find
// our bookmark.
XElement document = wordDocument.MainDocumentPart.GetXElement();
Bookmark bookmark = Bookmark.Find(document, BookmarkName);
// Act, getting the concatenated text contents of the bookmarked runs.
string text = bookmark.GetValue();
// Assert.
Assert.Equal("SecondThird", text);
}
}
}
You can find the full code example in my CodeSnippets GitHub repository. Look for the Bookmark and BookmarkTests classes and note that I'm using the Open-Xml-PowerTools.
You can obviously do more complicated things with those Open XML elements. This is just a simple example.

How do I fix this error when trying to use the Watson SDK for Unity?

thanks for taking a look at this. I'm new to Unity and struggling to understand how to fix this error.
Assets/Watson/Scripts/Logging/Logger.cs(115,53): error CS0311: The type IBM.Watson.DeveloperCloud.Logging.LogSystem' cannot be used as type parameter T in the generic type or method Singleton. There is no implicit reference conversion from IBM.Watson.DeveloperCloud.Logging.LogSystem' to `UnityEngine.MonoBehaviour
This is the line causing the error:
public static LogSystem Instance { get { return Singleton<LogSystem>.Instance; } }
And this is it in context:
/// <summary>
/// This singleton class maintains the of list of installed reactors and handles all LogRecord
/// objects. See the static class Log for functions the end user of this system should actually
/// be calling. This class is thread safe.
/// </summary>
public class LogSystem
{
#region Public Properties
/// <summary>
/// Returns the singleton instance of the Logger object.
/// </summary>
**public static LogSystem Instance { get { return Singleton<LogSystem>.Instance; } }**
#endregion
#region Private Data
private static bool sm_bInstalledDefaultReactors = false;
List<ILogReactor> m_Reactors = new List<ILogReactor>();
#endregion
#region Public Functions
public static List<ILogReactor> ReactorsInstalled
{
get
{
return LogSystem.Instance.m_Reactors;
}
}
/// <summary>
/// Install a default debug and file reactor.
/// </summary>
public static void InstallDefaultReactors(int logHistory = 2, LogLevel logLevelFileReactor = LogLevel.STATUS)
{
if (!sm_bInstalledDefaultReactors)
{
// install the default reactors...
sm_bInstalledDefaultReactors = true;
#if UNITY_EDITOR || UNITY_IOS || UNITY_ANDROID
LogSystem.Instance.InstallReactor(new DebugReactor());
#endif
if (!string.IsNullOrEmpty(Constants.Path.LOG_FOLDER) && !System.IO.Directory.Exists(Application.persistentDataPath + Constants.Path.LOG_FOLDER))
System.IO.Directory.CreateDirectory(Application.persistentDataPath + Constants.Path.LOG_FOLDER);
LogSystem.Instance.InstallReactor(new FileReactor(Application.persistentDataPath + Constants.Path.LOG_FOLDER + "/" + Application.productName + ".log", logLevelFileReactor, logHistory));
Application.logMessageReceived += UnityLogCallback;
}
}
static void UnityLogCallback(string condition, string stacktrace, LogType type)
{
if (type == LogType.Exception)
Log.Critical("Unity", "Unity Exception {0} : {1}", condition, stacktrace);
}
/// <summary>
/// Installs a reactor into this Logger.
/// </summary>
/// <param name="reactor">The reactor object.</param>
public void InstallReactor(ILogReactor reactor)
{
lock (m_Reactors)
{
m_Reactors.Add(reactor);
}
// set our default reactor flag to true if the user installs their own reactors.
sm_bInstalledDefaultReactors = true;
}
/// <summary>
/// Removes a reactor from this Logger.
/// </summary>
/// <param name="reactor">The reactor to remove.</param>
/// <returns>Returns true on success.</returns>
public bool RemoveReactor(ILogReactor reactor)
{
lock (m_Reactors)
{
return m_Reactors.Remove(reactor);
}
}
/// <summary>
/// Send the given LogRecord to all installed reactors.
/// </summary>
/// <param name="log">The LogRecord to pass to all reactors.</param>
public void ProcessLog(LogRecord log)
{
lock (m_Reactors)
{
foreach (var reactor in m_Reactors)
reactor.ProcessLog(log);
}
}
#endregion
}
public static LogSystem Instance
{
get
{
return instance;
}
}
private static LogSystem instance;
// Ctor of the class
public LogSystem()
{
if(instance == null) { instance = this;}
}
This is a very basic singleton pattern implementation. You can find more advanced ones online.

PowerShell provider relative path tab-completion issue

I've implemented a simple PowerShell NavigationCmdletProvider.
For those who don't know, this means I can create a snap-in with a cmdlet which is effectively a virtual filesystem drive; this drive can be mounted and navigated into from PowerShell like any normal folder. Each action against the drive (e.g., check if a path points to a valid item, get a list of names of child items in a folder, etc.) is mapped to a method of the .NET class inherited from the NavigationCmdletProvider class.
I'm facing a problem with tab-completion, and would like to find a solution. I've found that tab-completion gives incorrect results when using relative paths. For absolute paths, it works fine.
For those who don't know, tab completion for a NavigationCmdletProvider works through PowerShell calling the GetChildNames method, which is overridden from the NavigationCmdletProvider class.
--Demonstration of the issue--
Assume I have a provider, 'TEST', with the following folder hierarchy:
TEST::child1
TEST::child1\child1a
TEST::child1\child1b
TEST::child2
TEST::child2\child2a
TEST::child2\child2b
TEST::child3
TEST::child3\child3a
TEST::child3\child3b
Absolute paths:
If I type "dir TEST::child1\" and press tab a few times, it gives me the expected results:
> dir TEST::child1\child1a
> dir TEST::child1\child1b
Relative paths:
First, I navigate to "TEST::child1":
> cd TEST::child1
Then, if I type "dirspace" and press tab a few times, it gives me incorrect results:
> dir .\child1\child1a
> dir .\child1\child1b
I expect to see these instead:
> dir .\child1a
> dir .\child1b
Is this a bug in PowerShell, or am I doing something wrong?
Here's the complete, self-contained code for the provider:
[CmdletProvider("TEST", ProviderCapabilities.None)]
public class MyTestProvider : NavigationCmdletProvider
{
private Node m_Root;
private void ConstructTestHierarchy()
{
//
// Create the nodes
//
Node root = new Node("");
Node child1 = new Node("child1");
Node child1a = new Node("child1a");
Node child1b = new Node("child1b");
Node child2 = new Node("child2");
Node child2a = new Node("child2a");
Node child2b = new Node("child2b");
Node child3 = new Node("child3");
Node child3a = new Node("child3a");
Node child3b = new Node("child3b");
//
// Construct node hierarchy
//
m_Root = root;
root.AddChild(child1);
child1.AddChild(child1a);
child1.AddChild(child1b);
root.AddChild(child2);
child2.AddChild(child2a);
child2.AddChild(child2b);
root.AddChild(child3);
child3.AddChild(child3a);
child3.AddChild(child3b);
}
public MyTestProvider()
{
ConstructTestHierarchy();
}
protected override bool IsValidPath(string path)
{
return m_Root.ItemExistsAtPath(path);
}
protected override bool ItemExists(string path)
{
return m_Root.ItemExistsAtPath(path);
}
protected override void GetChildNames(string path, ReturnContainers returnContainers)
{
var children = m_Root.GetItemAtPath(path).Children;
foreach (var child in children)
{
WriteItemObject(child.Name, child.Name, true);
}
}
protected override bool IsItemContainer(string path)
{
return true;
}
protected override void GetChildItems(string path, bool recurse)
{
var children = m_Root.GetItemAtPath(path).Children;
foreach (var child in children)
{
WriteItemObject(child.Name, child.Name, true);
}
}
}
/// <summary>
/// This is a node used to represent a folder inside a PowerShell provider
/// </summary>
public class Node
{
private string m_Name;
private List<Node> m_Children;
public string Name { get { return m_Name; } }
public ICollection<Node> Children { get { return m_Children; } }
public Node(string name)
{
m_Name = name;
m_Children = new List<Node>();
}
/// <summary>
/// Adds a node to this node's list of children
/// </summary>
public void AddChild(Node node)
{
m_Children.Add(node);
}
/// <summary>
/// Test whether a string matches a wildcard string ('*' must be at end of wildcardstring)
/// </summary>
private bool WildcardMatch(string basestring, string wildcardstring)
{
//
// If wildcardstring has no *, just do a string comparison
//
if (!wildcardstring.Contains('*'))
{
return String.Equals(basestring, wildcardstring);
}
else
{
//
// If wildcardstring is really just '*', then any name works
//
if (String.Equals(wildcardstring, "*"))
return true;
//
// Given the wildcardstring "abc*", we just need to test if basestring starts with "abc"
//
string leftOfAsterisk = wildcardstring.Split(new char[] { '*' })[0];
return basestring.StartsWith(leftOfAsterisk);
}
}
/// <summary>
/// Recursively check if "child1\child2\child3" exists
/// </summary>
public bool ItemExistsAtPath(string path)
{
//
// If path is self, return self
//
if (String.Equals(path, "")) return true;
//
// If path has no slashes, test if it matches the child name
//
if(!path.Contains(#"\"))
{
//
// See if any children have this name
//
foreach (var child in m_Children)
{
if (WildcardMatch(child.Name, path))
return true;
}
return false;
}
else
{
//
// Split the path
//
string[] pathChunks = path.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
//
// Take out the first chunk; this is the child we're going to search
//
string nextChild = pathChunks[0];
//
// Combine the rest of the path; this is the path we're going to provide to the child
//
string nextPath = String.Join(#"\", pathChunks.Skip(1).ToArray());
//
// Recurse into child
//
foreach (var child in m_Children)
{
if (String.Equals(child.Name, nextChild))
return child.ItemExistsAtPath(nextPath);
}
return false;
}
}
/// <summary>
/// Recursively fetch "child1\child2\child3"
/// </summary>
public Node GetItemAtPath(string path)
{
//
// If path is self, return self
//
if (String.Equals(path, "")) return this;
//
// If path has no slashes, test if it matches the child name
//
if (!path.Contains(#"\"))
{
//
// See if any children have this name
//
foreach (var child in m_Children)
{
if (WildcardMatch(child.Name, path))
return child;
}
throw new ApplicationException("Child doesn't exist!");
}
else
{
//
// Split the path
//
string[] pathChunks = path.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
//
// Take out the first chunk; this is the child we're going to search
//
string nextChild = pathChunks[0];
//
// Combine the rest of the path; this is the path we're going to provide to the child
//
string nextPath = String.Join(#"\", pathChunks.Skip(1).ToArray());
//
// Recurse into child
//
foreach (var child in m_Children)
{
if (String.Equals(child.Name, nextChild))
return child.GetItemAtPath(nextPath);
}
throw new ApplicationException("Child doesn't exist!");
}
}
}
Not sure this is a bug, I found this workaround that seems to "do the job". (small update, turns out my original code would "bug out" when working your way down multiple levels.
''' <summary>
''' Joins two strings with a provider specific path separator.
''' </summary>
''' <param name="parent">The parent segment of a path to be joined with the child.</param>
''' <param name="child">The child segment of a path to be joined with the parent.</param>
''' <returns>A string that contains the parent and child segments of the path joined by a path separator.</returns>
''' <remarks></remarks>
Protected Overrides Function MakePath(parent As String, child As String) As String
Trace.WriteLine("::MakePath(parent:=" & parent & ",child:=" & child & ")")
Dim res As String = MyBase.MakePath(parent, child)
Trace.WriteLine("::MakePath(parent:=" & parent & ",child:=" & child & ") " & res)
If parent = "." Then
'res = ".\" & child.Split("\").Last
If String.IsNullOrEmpty(Me.SessionState.Path.CurrentLocation.ProviderPath) Then
res = parent & PATH_SEPARATOR & child
Else
res = parent & PATH_SEPARATOR & child.Substring(Me.SessionState.Path.CurrentLocation.ProviderPath.Length + 1)
'res = parent & PATH_SEPARATOR & child.Replace(Me.SessionState.Path.CurrentLocation.ProviderPath & PATH_SEPARATOR, String.Empty)
End If
Trace.WriteLine("::**** TRANSFORM: " & res)
End If
Return res
End Function
You can work around this if you design you provider so that it expects entering a non-empty Root when you create a new drive. I noticed that the tab-completion mistakenly suggest the complete child path instead of just the child name if the Root property of PSDriveInfo has not been set.
It can be limiting for some providers to always require a non-empty root. The workaround above works well if you don't want to make the users always enter some Root when creating a new drive.
I've listed this as a PowerShell provider bug in Microsoft Connect: Issue with relative path tab-completion (via Get-ChildNames) for NavigationCmdletProvider
If anyone can reproduce this, please visit the link and say so, because Microsoft probably won't look into this if only one person is reporting it.
It looks like this is fixed in PowerShell 3.0. I don't know why Microsoft doesn't want to fix this in older versions, it's not something any code could possibly depend on.
I was able to get it to work with overiding string[] ExpandPath(string path) and setting the ProviderCapabilities.ExpandWildcards capabilities.

Ado.net entity .include() method not working

I've got this function
public static AdoEntity.Inspector GetInspectorWithInclude(int id, List<string> properties)
{
using (var context = new Inspection09Entities())
{
var query = context.Inspector;
if (properties != null)
{
foreach (var prop in properties)
{
if (!string.IsNullOrEmpty(prop))
query.Include(prop);
}
}
return query.Where(i => i.ID == id).First();
}
}
which i use to get my "Inspectors" from the DB and an additional feature to specify what to "Include" with the data. So it takes a List<'string'> and includes them with the query. This function doesn't seem to work because the returned object still does not include the requested data. Could someone tell me what is wrong with this method/approach.
Thanks in advance.
Solution
Thank you to Misha N. suggestion, I have hatched this EF helper which extends the ObjectQuery class. Hopefully others may find it useful.
/// <summary>
/// The include extesion that takes a list and returns a object query with the included data.
/// </summary>
/// <param name="objectQuery">
/// The object query.
/// </param>
/// <param name="includes">
/// The list of strings to include.
/// </param>
/// <typeparam name="T">
/// </typeparam>
/// <returns>
/// An object query of T type with the included data.
/// </returns>
public static ObjectQuery<T> Include<T>(this ObjectQuery<T> objectQuery, List<string> includes)
{
ObjectQuery<T> query = objectQuery;
if (includes != null) includes.ForEach(s => { if (!string.IsNullOrEmpty(s)) query = query.Include(s); });
return query;
}
Usage example.
using(var context = new MyEntity())
{
var includes = new List<string>
{
"Address",
"Orders",
"Invoices"
}
return context.CustomerSet.Include(includes).First(c => c.ID == customerID);
}
Nothing is wrong with your approach, just one little thing need to be changed:
public static AdoEntity.Inspector GetInspectorWithInclude(int id, List<string> properties)
{
using (var context = new Inspection09Entities())
{
var query = context.Inspector;
if (properties != null)
{
foreach (var prop in properties)
{
if (!string.IsNullOrEmpty(prop))
query = query.Include(prop);// <--- HERE
}
}
return query.Where(i => i.ID == id).First();
}
}
ObjectQuery.Include() method is returning altered ObjectQuery object, you haven't been doing changes to the inital query.
Hope this helps