How to sort DBML objects alphabetically? - c#

I've got a DBML file in my project with all my LinqToSql objects. Initially I imported them from the DB, and all was well. Now as my DB has been growing, I've been adding the new tables to the diagram in the O/R Designer, but they always get appended to the end of the XML. This is a bit of a pain, because when I'm defining foreign keys, it always lists the available tables in the order in which they appear in the XML.
Any ideas how to sort the XML table declarations alphabetically according to the table name?

I know this is old, but I also want to sort the tables and functions in my DBML to make it more manageable in Git. The following console application code seems to work pretty well. You can drag and drop a DBML file onto the exe, or you could set up a bat file or build event in your project(s).
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Linq;
namespace DbmlSorter
{
class Program
{
static void Main(string[] args)
{
if (args.Length == 0)
return;
var fileName = args[0];
try
{
if (!File.Exists(fileName))
return;
SortElements(fileName);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
Console.WriteLine();
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
private static void SortElements(string fileName)
{
var root = XElement.Load(fileName);
var connections = new SortedDictionary<string, XElement>();
var tables = new SortedDictionary<string, XElement>();
var functions = new SortedDictionary<string, XElement>();
var others = new SortedDictionary<string, XElement>();
foreach (var element in root.Elements())
{
var key = element.ToString();
if (key.StartsWith("<Connection"))
connections.Add(key, element);
else if (key.StartsWith("<Table"))
tables.Add(key, element);
else if (key.StartsWith("<Function"))
functions.Add(key, element);
else
others.Add(key, element);
}
root.RemoveNodes();
foreach (var pair in connections)
{
root.Add(pair.Value);
Console.WriteLine(pair.Key);
}
foreach (var pair in tables)
{
root.Add(pair.Value);
Console.WriteLine(pair.Key);
}
foreach (var pair in functions)
{
root.Add(pair.Value);
Console.WriteLine(pair.Key);
}
foreach (var pair in others)
{
root.Add(pair.Value);
Console.WriteLine(pair.Key);
}
root.Save(fileName);
}
}
}

A possible solution is to write a small application that reads in the XML, sorts it to your liking and outputs the updated version.

Related

Reading file with Apache Arrow ArrowFileReader in .net

I am trying to read the content of an arrow file but I was not able to find the functions to get the actual data from it. I am not able to find any useful example to read the data too. For example here.
The code example for writing and reading in C#:
// Write
var recordBatch = new Apache.Arrow.RecordBatch.Builder(memoryAllocator)
.Append("Column A", false, col => col.Int32(array => array.AppendRange(Enumerable.Range(5, 15))))
.Build();
using (var stream = File.OpenWrite(filePath))
using (var writer = new Apache.Arrow.Ipc.ArrowFileWriter(stream, recordBatch.Schema, true))
{
await writer.WriteRecordBatchAsync(recordBatch);
await writer.WriteEndAsync();
}
// Read
var reader = Apache.Arrow.Ipc.ArrowFileReader.FromFile(filePath);
var readBatch = await reader.ReadNextRecordBatchAsync();
var col = readBatch.Column(0);
By debugging the code, I can see the values in the col Values property but I have no way of accessing this information in the code.
Am I missing anything or is there a different approach to read the data?
The Apache.Arrow package does not do any compute today. It will read in the file and you will have access to the raw buffers of data. This is sufficient for a number of intermediary tasks (e.g. services that shuttle data to and from or aggregate data files). So if you want to do a lot of operations on the data you may want some kind of dataframe library.
One such library is the Microsoft.Data.Analysis library which has added a DataFrame type which can be created from an Arrow RecordBatch. There is some explanation and examples of the library in this blog post.
I haven't worked with that library much but I was able to put together a short example of reading an Arrow file and printing the data:
using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;
using Apache.Arrow.Ipc;
using Microsoft.Data.Analysis;
namespace DataframeExperiment
{
class Program
{
static async Task AsyncMain()
{
using (var stream = File.OpenRead("/tmp/test.arrow"))
using (var reader = new ArrowFileReader(stream))
{
var recordBatch = await reader.ReadNextRecordBatchAsync();
Console.WriteLine("Read record batch with {0} column(s)", recordBatch.ColumnCount);
var dataframe = DataFrame.FromArrowRecordBatch(recordBatch);
var columnX = dataframe["x"];
foreach (var value in columnX)
{
Console.WriteLine(value);
}
}
}
static void Main(string[] args)
{
AsyncMain().Wait();
}
}
}
I created the test file with a small python script:
import pyarrow as pa
import pyarrow.ipc as ipc
tab = pa.Table.from_pydict({'x': [1, 2, 3], 'y': ['x', 'y', 'z']})
with ipc.RecordBatchFileWriter('/tmp/test.arrow', schema=tab.schema) as writer:
writer.write_table(tab)
You could presumably also create the test file using C# with Apache.Arrow's array builders.
Update (Using Apache.Arrow directly)
On the other hand, if you want to use Apache.Arrow directly, and still get access to the data, then you can use typed arrays (e.g. Int32Array, Int64Array). You will first need to determine the type of your array somehow (either through prior knowledge of the schema or as / is style checks or pattern matching).
Here is an example using Apache.Arrow alone:
using System;
using System.IO;
using System.Threading.Tasks;
using Apache.Arrow;
using Apache.Arrow.Ipc;
namespace ArrayValuesExperiment
{
class Program
{
static async Task AsyncMain()
{
using (var stream = File.OpenRead("/tmp/test.arrow"))
using (var reader = new ArrowFileReader(stream))
{
var recordBatch = await reader.ReadNextRecordBatchAsync();
// Here I am relying on the fact that I know column
// 0 is an int64 array.
var columnX = (Int64Array) recordBatch.Column(0);
for (int i = 0; i < columnX.Values.Length; i++)
{
Console.WriteLine(columnX.Values[i]);
}
}
}
static void Main(string[] args)
{
AsyncMain().Wait();
}
}
}
Adding to the second approach proposed by Pace, an utility function like below can be used to get the values
private static dynamic GetArrayData(IArrowArray array)
{
return array switch
{
Int32Array int32array =>int32array.Values.ToArray(),
Int16Array int16array => int16array.Values.ToArray(),
StringArray stringArray => stringArray.Values.ToArray(),
FloatArray floatArray => floatArray.Values.ToArray(),
Int64Array int64Array => int64Array.Values.ToArray(),
DoubleArray doubleArray => doubleArray.Values.ToArray(),
Time32Array time32Array => time32Array.Values.ToArray(),
Time64Array time64Array => time64Array.Values.ToArray(),
BooleanArray booleanArray => booleanArray.Values.ToArray(),
Date32Array date32Array => date32Array.Values.ToArray(),
Date64Array date64Array => date64Array.Values.ToArray(),
Int8Array int8Array => int8Array.Values.ToArray(),
UInt16Array uint6Array => uint6Array.Values.ToArray(),
UInt8Array uInt8Array => uInt8Array.Values.ToArray(),
UInt64Array uInt64Array => uInt64Array.Values.ToArray(),
_ => throw new NotImplementedException(),
};
}
then iterate over the recordBatch as
object[,] results = new Object[recordBatch.Length, recordBatch.ColumnCount];
var col = 0;
foreach (var array in recordBatch.Arrays)
{
var row = 0;
foreach (var data in GetArrayData(array))
{
results[row++, col] = data;
}
col++;
}
return results;
Worth noting however that StringArrays return Bytes so you need to convert to back to string for example using
System.Text.Encoding.Unicode.GetString(stringArray.Values)

Display csv read data in console application in c#

I am completely new to programming and trying to get the complete row data from csv file based on column value in c#. Example data is as follows:
Mat_No;Device;Mat_Des;Dispo_lvl;Plnt;MS;IPDS;TM;Scope;Dev_Cat
1111;BLB A601;BLB A601;T2;PW01;10;;OP_ELE;LED;
2222;ALP A0001;ALP A0001;T2;PW01;10;;OP_ELE;LED;
If user enters a Mat_No he gets the full row data of that particular number.
I have two files program.cs and filling.cs
overViewArea.cs contain following code for csv file reading:I dont know how to access the read values from program.cs file and display in console
`using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Data;
namespace TSDB
{
class fillData
{
public static fillData readCsv()
{
fillData getData= new fillData ();
using (var reader = new StreamReader(#"myfile.csv"))
{
List<string> headerList = null;
while (!reader.EndOfStream)
{
var line = reader.ReadLine();
if(headerList==null)
{
headerList = line.Split(';').ToList();
}
else
{
var values = line.Split(';');
for(int i = 0; i< headerList.Count; i++)
{
Console.Write(headerList[i] + "=" + values[i]+";");
}
Console.WriteLine();
}
}
}
return fillData;
}
}
}`
Program.cs has following code
class Program
{
static void Main(string[] args)
{
fillData data= fillData.readCsv();
Console.ReadLine();
}
}
First, please, do not reinvent the wheel: there are many CSV readers available: just use one of them. If you have to use your own routine (say, for a student project), I suggest extracting method. Try using File class instead of Stream/StreamReader:
// Simple: quotation has not been implemented
// Disclamer: demo only, do not use your own CSV readers
public static IEnumerable<string[]> ReadCsvSimple(string file, char delimiter) {
return File
.ReadLines(file)
.Where(line => !string.IsNullOrEmpty(line)) // skip empty lines if any
.Select(line => line.Split(delimiter));
}
Having this routine implemented, you can use Linq to query the data, e.g.
If user enters a Mat_No he gets the full row data of that particular
number.
Console.WriteLine("Mat No, please?");
string Mat_No_To_Filter = Console.ReadLine();
var result = ReadCsvSimple(#"myfile.csv", ';')
.Skip(1)
.Where(record => record[0] == Mat_No_To_Filter);
foreach (var items in result)
Console.WriteLine(string.Join(";", items));

How do I programmatically determine which WMI property is the primary key of a class?

I need to dynamically determine which property of a WMI class is the primary key in C#.
I can manually locate this information using CIM Studio or the WMI Delphi Code Creator but I need to find all property names of a class and flag which is / are the key / keys... and I already know how to find the property names of a class.
Manual identification of the key is covered in a related answer and I'm hoping the author (I'm looking at RRUZ) might be able to fill me in on how they locate the key (or anyone else who might know).
Many thanks.
To get the key field of a WMI class, you must iterate over the qualifiers of the properties for the WMI class and then search for the qualifier called key and finally check if the value of that qualifier is true.
Try this sample
using System;
using System.Collections.Generic;
using System.Management;
using System.Text;
namespace GetWMI_Info
{
class Program
{
static string GetKeyField(string WmiCLass)
{
string key = null;
ManagementClass manClass = new ManagementClass(WmiCLass);
manClass.Options.UseAmendedQualifiers = true;
foreach (PropertyData Property in manClass.Properties)
foreach (QualifierData Qualifier in Property.Qualifiers)
if (Qualifier.Name.Equals("key") && ((System.Boolean)Qualifier.Value))
return Property.Name;
return key;
}
static void Main(string[] args)
{
try
{
Console.WriteLine(String.Format("The Key field of the WMI class {0} is {1}", "Win32_DiskPartition", GetKeyField("Win32_DiskPartition")));
Console.WriteLine(String.Format("The Key field of the WMI class {0} is {1}", "Win32_Process", GetKeyField("Win32_Process")));
}
catch (Exception e)
{
Console.WriteLine(String.Format("Exception {0} Trace {1}", e.Message, e.StackTrace));
}
Console.WriteLine("Press Enter to exit");
Console.Read();
}
}
}
For those interested I've expanded on RRUZ's answer by:
allowing the query to be run against a remote machine, and
adding support for classes with multiple primary keys (as is the case with Win32_DeviceBus).
static void Main(string[] args)
{
foreach (var key in GetPrimaryKeys(#"root\cimv2\win32_devicebus"))
{
Console.WriteLine(key);
}
}
static List<string> GetPrimaryKeys(string classPath, string computer = ".")
{
var keys = new List<string>();
var scope = new ManagementScope(string.Format(#"\\{0}\{1}", computer, System.IO.Path.GetDirectoryName(classPath)));
var path = new ManagementPath(System.IO.Path.GetFileName(classPath));
var options = new ObjectGetOptions(null, TimeSpan.MaxValue, true);
using (var mc = new ManagementClass(scope, path, options))
{
foreach (var property in mc.Properties)
{
foreach (var qualifier in property.Qualifiers)
{
if (qualifier.Name.Equals("key") && ((System.Boolean)qualifier.Value))
{
keys.Add(property.Name);
break;
}
}
}
}
return keys;
}

How do you parse large SQL scripts into batches?

I have a very large sql file I want to break up into batches for execution.
I want to make sure I'm parsing it the same way that SSMS and SQLCMD do.
Microsoft has a great mixed mode assembly named Microsoft.SqlServer.BatchParser with a class named Parser that seams like it would do the trick.
It wants an implementation of IBatchSource as an argument to SetBatchSource before calling Parse().
Where can I find an implementation of IBatchSource, and more information on how to make use of this functionality?
I found the assembly Microsoft.SqlServer.BatchParser in the GAC along with it's friend Microsoft.SqlServer.BatchParserClient that contains implementations the interface IBatchSource.
namespace Microsoft.SqlServer.Management.Common
{
internal class BatchSourceFile : IBatchSource
internal class BatchSourceString : IBatchSource
}
The following conversation then occurred.
Assembly: Hello! My name is
Microsoft.SqlServer.Management.Common.ExecuteBatch. Would you like to StringCollection GetStatements(string sqlCommand)?
Me: Yes, I would, BatchParserClient assembly. Thanks for asking!
Repeatable Instructions (Do try this at home!)
Install Microsoft SQL Server 2008 R2 Shared Management Objects
Copy Microsoft.SqlServer.BatchParser.dll and Microsoft.SqlServer.BatchParserClient.dll from the GAC to a folder in your solution.
Reference Microsoft.SqlServer.BatchParser & Microsoft.SqlServer.BatchParserClient
Program.cs
using System;
using System.Collections.Specialized;
using System.IO;
using System.Text;
using Microsoft.SqlServer.Management.Common;
namespace ScriptParser
{
class Program
{
static void Main(string[] args)
{
ExecuteBatch batcher = new ExecuteBatch();
string text = File.ReadAllText(#"Path_To_My_Long_Sql_File.sql");
StringCollection statements = batcher.GetStatements(text);
foreach (string statement in statements)
{
Console.WriteLine(statement);
}
}
}
}
App.Config
<?xml version="1.0"?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5"/>
</startup>
</configuration>
Another option is to use the ScriptDom as described in this answer: https://stackoverflow.com/a/32529415/26877.
using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.SqlServer.TransactSql.ScriptDom;
namespace ScriptDomDemo
{
class Program
{
static void Main(string[] args)
{
TSql120Parser parser = new TSql120Parser(false);
IList<ParseError> errors;
using (StringReader sr = new StringReader(#"create table t1 (c1 int primary key)
GO
create table t2 (c1 int primary key)"))
{
TSqlFragment fragment = parser.Parse(sr, out errors);
IEnumerable<string> batches = GetBatches(fragment);
foreach (var batch in batches)
{
Console.WriteLine(batch);
}
}
}
private static IEnumerable<string> GetBatches(TSqlFragment fragment)
{
Sql120ScriptGenerator sg = new Sql120ScriptGenerator();
TSqlScript script = fragment as TSqlScript;
if (script != null)
{
foreach (var batch in script.Batches)
{
yield return ScriptFragment(sg, batch);
}
}
else
{
// TSqlFragment is a TSqlBatch or a TSqlStatement
yield return ScriptFragment(sg, fragment);
}
}
private static string ScriptFragment(SqlScriptGenerator sg, TSqlFragment fragment)
{
string resultString;
sg.GenerateScript(fragment, out resultString);
return resultString;
}
}
}

Opening mp3 by not-default program C sharp

How can I open mp3 file with RealPlayer while the default is MediaPlayer
I know Process and ProcessStartInfo method, but I would like to know how to "open program with..."
Can you help me, plz?
Okay, so thought I'd make this possible for you before I clock off for the night. I have thrown together a working console application which loads (known) installed programs from the registry's App Path key. The solution is far from perfect, won't be the safest, fastest, or most reliable solution, and it certainly shouldn't be seen amongst any production code, but it is more than enough to aid you, hopefully, in developing what it is you need:
So, here is the code, minus the namespace...
using System;
using System.IO;
using Microsoft.Win32;
using System.Diagnostics;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
if (args.Length >= 0 && !string.IsNullOrEmpty(args[0]) && File.Exists(args[0]))
{
var programs = new InstalledPrograms();
var programKey = "RealPlay.exe".ToLowerInvariant();
if (programs.ContainsKey(programKey))
{
var programPath = programs[programKey];
if (!string.IsNullOrEmpty(programPath) && File.Exists(programPath))
{
var process = new Process();
process.StartInfo = new ProcessStartInfo(programPath);
process.StartInfo.Arguments = args[0];
if (process.Start())
{
Console.WriteLine("That was easy!");
}
else
{
Console.WriteLine("Hell's bells and buckets of blood, we seem to have hit a snag!");
}
}
}
}
else
{
Console.WriteLine("Specify a file as an argument, silly!");
}
Console.WriteLine();
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
class InstalledPrograms : Dictionary<string, string>
{
static string PathKeyName = "Path";
static string RegistryKeyToAppPaths = #"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths";
public InstalledPrograms()
{
Refresh();
}
public void Refresh()
{
Clear();
using (var registryKey = Registry.LocalMachine.OpenSubKey(RegistryKeyToAppPaths))
{
var executableFullPath = string.Empty;
foreach (var registrySubKeyName in registryKey.GetSubKeyNames())
{
using (var registrySubKey = registryKey.OpenSubKey(registrySubKeyName))
{
executableFullPath = registrySubKey.GetValue(string.Empty) as string;
Add(registrySubKeyName.ToLowerInvariant(), executableFullPath);
}
}
}
}
}
}
Though we check for file existence, and other minor but necessary checks are made, you would still need to tighten this up further when plugged into the environment of your own code, including, among other things, exception handling for, but not limited to, registry access issues.

Categories