Passing multiple values to same column in the lambda query C# - c#

Hello I am trying to create a query where in the where clause i need to pass multiple values to the same column and i have built a query using string builder.
My actual Lambda query was
crentitiesbkp.Filter = obj =>
{
SPFetchCREntity entity = obj as SPFetchCREntity;
return obj.ToString() != null && entity.SW_Version==getmuid;
};
Here i changed the entity.SW_Version==getmuid like this
crentitiesbkp.Filter = obj =>
{
SPFetchCREntity entity = obj as SPFetchCREntity;
return obj.ToString() != null + cquery.ToString();
};
so the cquery is built and looks like this
&& entity.SW_Version=="TEST" && entity.SW_Version=="Result"
But its not filtering as per the query. Is this because this is passed as string ?
The cquery is built like this
foreach (var objj in storemuid)
{
cquery.Append(" && entity.SW_Version ==" +"\""+ objj.Value + "\"");
}

I resolved this scenario by using dictionary
Dictionary<string, List<SPFetchCREntity>> objDic = new Dictionary<string, List<SPFetchCREntity>>();
List<SPFetchCREntity> sp = new List<SPFetchCREntity>();
foreach (string str in objDic.Keys)
{
sp.AddRange(objDic[str]);
}
CRmappings2 = new ObservableCollection<SPFetchCREntity>(sp.ToList());
crentitiesbkp = CollectionViewSource.GetDefaultView(CRmappings2);
}
So now based on my checkbox selection i remove and add values from dictionary which works perfect for me now. This can be of any help to starter programmers like me .

Related

C# Linq Registry values to DataTable

I am trying to enumerate the registry to fetch a list of installed applications and return them via Linq to a DataTable in C#.
I have tried various things including sanitizing it as XML (which worked), however it seemed rather inefficient as ultimately, i require this as DataTable object.
Here is where i am at currently:
//Warning
public static DataRow DataRowInstalledApplication (this RegistryKey rgkey, string keyName)
{
RegistryKey key = rgkey.OpenSubKey(keyName, false);
try
{
//Application Name is mandetory for a given key.
if (key == null|| key.RegToString("DisplayName", false) == null )return null;
//Build a sanitised data row
var rowBuilder = new DataTable().NewRow();
rowBuilder["DisplayName"] = key.RegToString("DisplayName");
rowBuilder["UninstallString"] = key.RegToString("UninstallString");
rowBuilder["InstallLocation"] = key.RegToString("InstallLocation");
rowBuilder["Publisher"] = key.RegToString("Publisher");
rowBuilder["DisplayIcon"] = key.RegToString("DisplayIcon");
return rowBuilder;
}
finally
{
if (key != null) key.Close();
}
}
Here is the method that contains the Linq:
public DataTable GetRegistryApplicationDataTable(RegistryKey registryKey, string tableName)
{
if (registryKey != null)
{
try
{
//change to throw non critical error
var installedListXml = new DataTable(tableName, from name in registryKey.GetSubKeyNames()
let app = registryKey.DataRowInstalledApplication(name)
select app);
return installedListXml;
}
catch
{
return new DataTable(tableName);
}
finally
{
registryKey.Close();
}
}
return null;
}
The main problem i have is that i do not really understand Linq very well. Mainly how individual values are used during the iteration to call other things similar to
foreach (string value in collection)
{
Somefunction(value);
}
, in the case of the registry values i am trying to retrieve, i do not understand how to make a Linq query pass each key name to function, which will generate a row and the Linq Query return as a data table.
I would be grateful of any pointers! thanks
ps i call the above with
private static readonly RegistryKey HKLMUninstallKey = Registry.LocalMachine.OpenSubKey(#"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall");
GetRegistryApplicationDataTable(HKLMUninstallKey, "Computer")
and expect back a data table called computer.
Your first problem is your linq statement. You are trying to pass an IEnumerable into a constructor that is expecting either a (string) or a (string, string). If you modify your logic to this:
var query = from name in registryKey.GetSubKeyNames()
let app = registryKey.DataRowInstalledApplication(name)
select app;
foreach(var result in query)
{
var installedListXml = new DataTable(tableName, result);
}
That would work IF result was actually a string, but it's a DataRow, which is not a valid parameter for a DataTable constructor. Instead, there is an extension method you can call on the resulting query to copy to a data table, like so:
var query = from name in registryKey.GetSubKeyNames()
let app = registryKey.DataRowInstalledApplication(name)
select app;
var installedListXml = query.CopyToDataTable();
When you write a LINQ query statement, it is not executed until you try to enumerate over the results. CopyToDataTable does this, so if you were to step through your code you will notice that your function DataRowInstalledApplication will not be called until you call CopyToDataTable and not when you first assign query. The result you receive is an Enumerator that you can treat just like any other, whether that's using in a foreach loop or calling ToList or so forth. Inside the linq query itself, you are actually iterating over other values, in this case GetSubKeyNames. It would be functionally equivalent if you were to do this instead:
var dataRows = new List<DataRow>();
foreach(var name in registryKey.GetSubKeyNames())
{
dataRows.Add(registryKey.DataRowInstalledApplication(name));
}
return dataRows.CopyToDataTable();

Serializing a list of dynamic objects to a CSV with ServiceStack.Text

All of my EF classes have a Projection() method that helps me choose what I want to project from the class to the SQL queries:
Example:
public static Expression<Func<Something, dynamic>> Projection()
{
return e => new
{
something = e.SomethingId,
name = e.Name,
requiredThingId = e.RequiredThingId,
requiredThing = new
{
requiredThingId = e.RequiredThing.RequiredThingId,
name = e.RequiredThing.Name,
...
},
optionalThingId = e.OptionalThingId,
optionalThing = e.OptionalThingId == null ? null : new
{
optionalThingId = e.OptionalThing.OptionalThingId,
name = e.OptionalThing.Name
}
...
};
}
I use these projection methods like this:
List<dynamic> projected = dbContext.Something.Select(Something.Projection()).ToList();
This way lets me reuse my projections all around my project.
I want to use ServiceStack.Text to serialize these lists to CSV.
I'm doing this:
string csvString = CsvSerializer.SerializeToCsv<dynamic>(Something.Select(Something.Projection()).ToList());
byte[] csvBytes = System.Text.Encoding.Unicode.GetBytes(csvString);
return File(csvBytes, "text/csv", "foo.csv");
But the result is an empty csv (csvString is full of "\r\n"'s and nothing more)
Questions:
Am I using correctly the SerializeToCsv() method?
Can I use <dynamic> in this library?
Suggestions for achieving my purpose?
For the example above the desired CSV would flatten all the properties, something like:
"somethingId";"name";"requiredThingId";"requiredThing.requiredThingId";"requiredThing.name";"optionalThingId";"optionalThing.optionalThingId";"optionalThing.name"
I will answer my own questions, but will not mark as accepted in hope of a new greater answer..
Am I using correctly the SerializeToCsv() method? Can I use dynamic
in this library?
Answer: Yes to both but ServiceStack.Text v4.0.36 is needed (which is available at MyGet, not Nuget)
Suggestions for achieving my purpose?
Answer: With ServiceStack.Text it is possible to serialize to CSV a List<dynamic>, but all the nested properties will be rendered as JSON and they will not be flattened out, eg:
List<dynamic> list = new List<dynamic>();
list.Add(new
{
name = "john",
pet = new
{
name = "doggy"
}
});
string csv = CsvSerializer.SerializeToCsv(list);
This list will be serialized to this csv:
name, pet
"john", { name = "doggy" }
And not to this csv, as I was expecting:
name, pet_name
"john", "doggy"
So... I finally ended up writing this code:
public class CsvHelper
{
public static string GetCSVString(List<dynamic> inputList)
{
var outputList = new List<Dictionary<string, object>>();
foreach (var item in inputList)
{
Dictionary<string, object> outputItem = new Dictionary<string, object>();
flatten(item, outputItem, "");
outputList.Add(outputItem);
}
List<string> headers = outputList.SelectMany(t => t.Keys).Distinct().ToList();
string csvString = ";" + string.Join(";", headers.ToArray()) + "\r\n";
foreach (var item in outputList)
{
foreach (string header in headers)
{
if (item.ContainsKey(header) && item[header] != null)
csvString = csvString + ";" + item[header].ToString();
else
csvString = csvString + ";";
}
csvString = csvString + "\r\n";
}
return csvString;
}
private static void flatten(dynamic item, Dictionary<string, object> outputItem, string prefix)
{
if (item == null)
return;
foreach (PropertyInfo propertyInfo in item.GetType().GetProperties())
{
if (!propertyInfo.PropertyType.Name.Contains("AnonymousType"))
outputItem.Add(prefix + "__" + propertyInfo.Name, propertyInfo.GetValue(item));
else
flatten(propertyInfo.GetValue(item), outputItem, (prefix.Equals("") ? propertyInfo.Name : prefix + "__" + propertyInfo.Name));
}
}
}
What this does is:
It flattens the List, so that all the properties of the objects in the list are primitives (eg: no nested properties)
It creates a CSV from that flattened list.
This algorithm is O(n*m), being
n: number of items in the list
m: number of properties inside each item (including nested properties)
Whilst the recommendation is to use clean POCO's for Serialization, you can serialize in-line anonymous types, e.g:
var somethings = dbContext.Something.Select(e => new {
something = e.SomethingId,
name = e.Name
});
somethings.ToCsv().Print();
Otherwise I've just added support for serializing IEnumerable<object> and IEnumerable<dynamic> in this commit.
This change is available from v4.0.36+ that's now available on MyGet.
I believe that part of what is going on is that the library is using properties in the object to determine what to serialize. I believe that a dynamic object does not construct properties like it's a POCO. If you don't setup a getter and setter on your object, it certainly won't work. Just for reference, I using version 4.5.6.0 of this library.

Building a Dynamic Linq Query using Equals and an Array

I have been trying to solve the syntax for a dynamic linq query that is needed in my application.
I have a dynamic query that the where clause needs to be specified to either
GuidPrimaryKey is contained in a list of Guid OR
GuidPrimaryKey is equal to an item in a list of Guid (using some type of for-loop)
I have a Guid[] populated with over 5,000 keys. My Query is set up as
If I do this (as a test) it is successful
data = data.where("GuidPrimaryKey.Equals(#0)",array[0]);
as well as
data = data.where("GuidPrimaryKey.Equals(#0) OR GuidPrimaryKey.Equals(#1)",array[0], array[1]);
I have tried:data = data.where("GuidPrimaryKey.Contains(#0)",array); but that gives an error: No applicable method 'Contains' exists in type 'Guid'.
I also tried setting a loop to go through the elements in the array and set the where clause as a giant string, but that did not work either.
string s = "";
string p = ""
int counter = 0;
foreach(Guid g in Array)
{
s+= "GuidPrimaryKey.Equals(#" counter.ToString() + ") OR";
p += "Array[" counter.ToString() + "],";
counter++;
}
s = s.remove(s.length - 3, 3);
p = p.remove(p.length - 1, 1);
data = data.Where(s,p);
This gives me the error message: No Property or field '1' exists in type 'DynamicClass1'
Any ideas? I need to have the where clause build the query to check to see if the primary key (GuidPrimaryKey) exists in the list of keys (Guid[]).
I'm not sure if this works in the standard Dynamic Linq library, but I just tried this is my open-source version, and it works well:
var data = data.Where("GuidPrimaryKey in #0", array);
This also works:
var data = data.Where("#0.Contains(GuidPrimaryKey)", array);
Here is a full unit test I wrote to confirm this:
[TestMethod]
public void ExpressionTests_ContainsGuid()
{
//Arrange
//Generate some users with Id fields of type Guid
var userList = User.GenerateSampleModels(5, false);
var userQry = userList.AsQueryable();
//Generate a list of values that will fail.
var failValues = new List<Guid>() {
new Guid("{22222222-7651-4045-962A-3D44DEE71398}"),
new Guid("{33333333-8F80-4497-9125-C96DEE23037D}"),
new Guid("{44444444-E32D-4DE1-8F1C-A144C2B0424D}")
};
//Add a valid Guid so that this list will succeed.
var successValues = failValues.Concat(new[] { userList[0].Id }).ToArray();
//Act
var found1 = userQry.Where("Id in #0", successValues);
var found2 = userQry.Where("#0.Contains(Id)", successValues);
var notFound1 = userQry.Where("Id in #0", failValues);
var notFound2 = userQry.Where("#0.Contains(Id)", failValues);
//Assert
Assert.AreEqual(userList[0].Id, found1.Single().Id);
Assert.AreEqual(userList[0].Id, found2.Single().Id);
Assert.IsFalse(notFound1.Any());
Assert.IsFalse(notFound2.Any());
}

remove null column from collection in c#

I have a table Menu and the data is like the attached screen shot
Database table
and I want output like below image,
Means all the null values or integer ==0 should be hidden.
Right now I am showing these 5 columns only as you can see in 2nd screen shot..
I have something like this..
List<Menu> lstMenus = obj.GetMenus(10);
My code is
var menus = new List< dynamic >();
foreach (Menu menuBE in lstMenus)
{
dynamic menu = new
{
menuBE.MenuID,
menuBE.ParentMenuID,
menuBE.LinkText,
menuBE.ScreenName,
menuBE.Parameters,
menuBE.URL
// if(menuBE.Parameters.Length>0 ){ Parameters = menuBE.Parameters,}
};
menus.Add(menu);
}
and I want to put some condition like the last commented line in foreach loop. If menuBE.Parameters.Length>0 then this Parameters column should add be in dynamic menu else not.
Any idea how it can be done?
What I understood, in the opposite of James & techloverr, you want to keep records with parameter null:
foreach (Menu menuBE in lstMenus){
if (menuBE.Parameters.Length > 0){
dynamic menu = new{
menuBE.MenuID,
menuBE.ParentMenuID,
menuBE.LinkText,
menuBE.ScreenName,
menuBE.Parameters,
menuBE.URL
};
}
else {
dynamic menu = new{
menuBE.MenuID,
menuBE.ParentMenuID,
menuBE.LinkText,
menuBE.ScreenName,
menuBE.URL
};
}
menus.Add(menu);
}
** UPDATE **
As I understand in the whole question, you do not want a property Parameters when source data have Parameters.Lenght == 0, and that's why you are using dynamic type.
It's different from "that's OK have a property 'Parameters = null'". If that's the approach, you don't need to use dynamic type. Just add items as list-item of a declarated strong-type variable or list-item of anonymous type.
With the dynamic type you add properties at declaration time. So, you have to separate the different assigns as the code above.
If you want to put if outside to avoid duplicate code, you use ExpandoObject:
var m = new List<System.Dynamic.ExpandoObject>();
foreach (string item in new string[] { "a", "b", "c" }) {
dynamic menuItem = new System.Dynamic.ExpandoObject();
menuItem.pos1 = item;
menuItem.pos2 = (item == "b" ? item : null); // wrong
if (item == "c") { // correct
menuItem.pos3 = "I am at third iteration";
}
m.Add(menuItem);
}
See, if you put a breakpoint at m.Add(menuItem); these are the results:
case item == "a":
menuItem.pos1 = "a";
menuItem.pos2 = null; // wrong: pos2 must not exists
case item == "b":
menuItem.pos1 = "b";
menuItem.pos2 = "b";
case item == "c":
menuItem.pos1 = "c";
menuItem.pos2 = null; // wrong: pos2 must not exists
menuItem.pos3 = "I am at third iteration"; // correct: pos3 only exists here.
you can use this code snippet
foreach (Menu menuBE in lstMenus)
{
dynamic menu = new
{
MenuID = menuBE.MenuID,
ParentMenuID = menuBE.ParentMenuID,
LinkText = menuBE.LinkText,
ScreenName = menuBE.ScreenName,
URL = menuBE.URL,
Parameters = (menuBE.Parameters.Length>0) ? menuBE.Parameters : null
};
menus.Add(menu);
}

How to get a max value of a field from mongo cursor in C#

The complete method should be generic like
public string strGetMaxValue(string strDBName, string strCollectionName, string strKey)
{
// in this method if pass some prms it should give max value
}
The one i tried is
string strMaxValue = "";
MongoServer objServer = this.ConnectToServer();
if ((strDBName != null || strDBName != "") && (strCollectionName != null || strCollectionName != ""))
{
string[] strArrays = new string[1];
strArrays[0] = strKey;
//MongoCursor<BsonDocument> objCursor = objServer.GetDatabase(strDBName).GetCollection(strCollectionName).Find(query).SetSortOrder(SortBy.Descending(strArrays)).SetLimit(1);
var objCursor = objServer.GetDatabase(strDBName).GetCollection(strCollectionName).FindAll().SetSortOrder(SortBy.Descending(strArrays)).SetLimit(1).ToArray();
}
In that objCursor i m getting that document which i need.
i want to extract that field value and needs to send it as return parameter.
The method should be generic as such the key value may a field in nested document also.
how to achieve this.?
The method you are looking for is SetFields(params string[] fields) - it can be called on a cursor. It will limit your result set to just the fields you pass in (array) as well as the id. You can then index the field using the []
var result = server
.GetDatabase(strDBName)
.GetCollection(strCollectionName)
.FindAll()
.SetSortOrder(SortBy.Descending(new [] {strKey}))
.SetFields(new [] {strKey}) // The way to wrap something in an array for reference
.SetLimit(1)
.FirstOrDefault(); // Will return null if there are no rows
// There is a chance that we have no results
if (result != null)
// You might want to make sure this is a string / add the datatype
// as a Generic T to your function
return result[strKey].AsString;
else
return null;

Categories