Remove a property/column from a generic list - c#

Due to some reason I cannot change the query so I have to do this in C#.
I have a class:
public class myClass
{
int id { get; set; }
string name { get; set; }
DateTime sDate { get; set; }
bool status { get; set; }
}
The data I am getting is fetched in this list. Now what I want is to remove those properties from a list that has null values. I may sound insane but you read it right. I thought of creating another list with only the selected properties, but any of the above properties can be null. So I have to devise a mechanism to filter my list based on this.
For more clarity consider the following example.
List<myClass> lstClass = some data source.
After getting the data the generic list(lstClass) looks like this.Consider the result set in a table:
Id Name Sdate status
1 a null null
2 b null null
3 c null false
Can i some how make my list look like this after removing the property sdate.
So the new list that I want to create should have only three properties.
Id Name status
1 a null
2 b null
3 c false
Any ideas? Can I do this using Linq?
PS: This has nothing to do with presentation. I don’t have a grid where I am not able to hide columns that Is not what I am looking for.

Assuming you have a generic list of myClass instances, you can create an anonymous type with only the needed properties:
List<myClass> list = ...;
var reducedList = list.Select(e => new {e.id, e.name, e.status}).ToList();
// note: call to ToList() is optional
foreach (var item in reducedList)
{
Console.WriteLine(item.id + " " + item.name + " " + item.status);
//note: item does not have a property "sDate"
}

I'm not sure you should solve your issue in the Data, but rather it's a presentation problem.
In which control do you want to display it ? Let's say you display it in DataGrid with AutoGenerateColumns=True, then you can 1) loop on columns/properties 2) for each column/property see if all property values for all rows are null and if so set column's visibility to Collapsed.
If you generate your columns by yourself it's even simpler : only add columns when content is not null for all rows.
If your DB content is dynamic, you might want to bind each row's visibility to a property that would state wether all rows are null or not for that property. Depending on how generic you want your code to be, the code might be very different, and in case you want to have generic solution, using Reflection to retrieve/get/set properties might be of some use.

Related

How to Pivot a List<T> and assign to a GridView without the use of DataTable?

I am currently preparing my Application to transition over to MVC and in doing so have replaced all SQL statements with LINQ (EF) and removing all Datasets/DataTables, replacing them with strongly typed Lists.
I am stuck on one scenario where I need to pivot a strongly typed List<T> , after I pivot (number of columns produced vary) I am attempting to re-assign the results back to the GridView, keeping in mind that I don't want to use a DataTable.
I have looked at various examples where people are attempting to use ExpandoObject but I can't get it to work and continue to get this error:
The data source for GridView with id 'GridReport' did not have any properties or attributes from which to generate columns. Ensure that your data source has content.
The alternative would be to create some kind of class dynamically with properties getter and setter, would this be the right approach?
Given that eventually I will discard GridView too in MVC (controls not supported) I am now just thinking to maybe create an output just using HTML table? Since all I am doing is outputting the display and not using the GridView for any other purpose.
Some guidance and code example would help for the right scenario.
My List <T> looks like this (shortened for simplicity) and I pivot on ticker_id using a GroupBy. Am I able to return the property names from the Linq query too? if so how?:
public class CorporationCompare
{
public int ticker_id { get; set; }
public string tickerSymbol { get; set; }
public decimal? price { get; set; }
}
//pivot
var query = (from item in lstCompareCorp
let key = new { ticker_id = item.ticker_id }
group new { tickerSymbol = item.tickerSymbol, price = item.price } by key)
.ToList();
Before Pivot:
ticker_id tickerSymbol price
1 GOOG 123.45
208 AAPL 543.21
After Pivot:
ticker_id 1 208
tickerSymbol GOOG AAPL
price 123.45 543.21

mongodb C# error on first Push

I've a Parent Entity that has a property of list of Child Entities. Initially on Insert I don't have values for the child entities.
But when I try to Update(by calling push) the document with Child Entities it fails.
This works when I insert a dummy child entity value to the Initial Add .
This is because the embedded document refers to null .
public class ParentDocument : Entity
{
public string prop1 { get; set; }
public List<EmbeddedDocument> EmbeddedDocuments { get; set; }
}
public class EmbeddedDocument
{
public string prop2{ get; set; }
}
The parent is saved First
_collection.InsertOne(new ParentDocument(){prop1 ="value"});
and later when I Update the document
var builder = Builders<ParentDocument>.Update;
var updateDefintion = builder.Push(x => x.EmbeddedDocuments ,new EmbeddedDocument() { prop2= "value2" });
_collection.UpdateManyAsync(x=>x.Id==ParentDocumentId, updateDefinition)
error occurs "A write operation resulted in an error mongodb"
But this push works if I have already inserted Embedded Document(s) in the List on first insert.
I think that is because of that the EmbeddedDocuments property is Inserted as null the push doesn't work.
I also tried passing empty List to intial Insert,but not helped.
One Idea would be to check if the count of List of Embedded documents is zero and call
Builder.set(x=>x.EmbeddedDocuments ,new List<EmbeddedDocument>(){ item1 });
But this will cost a query , which I don't want to.
Is there any other solution?
Thanks in Advance
To Hazard a guess, it's because the "array" field in the database is null after the insert. You either need to make the initial value in the database an empty array, or you need to make it not-present. You can either:
use the [BsonIgnoreIfDefault] attribute on your list field to not store nulls,
Initialize your list field to an empty list to store an empty array
This can be reproduced in the shell very easily:
> db.so.insert({x:1, y: null})
> db.so.update({x:1}, {$push: { y: "funny" }})
This will error. However, if you remove y from the insertion or change it to an empty array, the update will succeed.

Display class object in GridView

I have such a situaton, that I am reading txt file making some operation on the lines and at the end I want to display everything in gridview. I have 3 separated columns. In first and second one I am displaying normal string values. But in middle one I have object returned by one class and I would like to display it normally in my gridview. How can I achieve it? I have something like this so far.
while ((line = sr.ReadLine()) != null)
{
string[] lines = line.Split(",".ToCharArray());
object returnValue;
MyColumns object = new MyColumns();
object.Time = line[0];
object.System_Description = line[1];
object.User_Description = line[2];
///earlier in my code I have object of class called method
returnValue = method.MyMethod(mc.System_Description);
Class main = new Class();
main.Data1= object.Time;
main.ProblemData= returnValue;
main.Data2= object.User_Description;
list3.Add(main);
}
this.dataGridView3.DataSource = list3;
I have problem with showing ProblemData. Now in this column gridview shows me "project_name.Class_Name" (name of the class that this value was retured by)
EDIT:
Ok, I also have to mention that this class, from which returnValue gets values has 5 properties, let's say Categry, Name, Second_Name, Status and Value. This returnValue holds all this 5 properties with their current values.
EDIT2: Maybe someone knows how to display all this fields in one column? How can I join them only for displaying purpose? When I make normal List and insert this returnValue, it creates these 5 columns and insert values inside. Maybe it will make it easier to understand.
Please see my first comment on your question.
You have to use a nested GridView inside your second column which will bind to the returnValue. This is because GridView cannot automatically cascade your object datasource. The inner binding needs to be done in the RowDataBound event of your main GridView. For this to work, you will have to re-organise / re-factor your code.
Alternatively, you can concatenate the properties of the returnValue if their string representations can work for your scenario.
Edit:
The OP is asking about WinForms DataGridView (not ASP.Net):
The WinForms DataGridView does not support nesting out-of-the-box. However, there are some templating workarounds which are complicated. You are looking for a simple solution. I found one which can serve your immediate needs.
Hook into the CellFormatting event.
if (e.value is YOUR_OBJECT_TYPE) {
e.Value = (e.Value as YOUR_OBJECT_TYPE).YOUR_PROPERTY_NAME;
}
For details please refer to this: Binding to Nested Properties
Alternate option:
The alternate option of concatenating the properties of the returnValue as string, will also work.
main.ProblemData = "Cat: " + returnValue.Category + ", Name: " + returnValue.Name;
you should have defined your class variables like a propertiesbecause you are using them in databinding. like this..
public String Data1 {get;set;}
also make your list a ObservableCollection as it will notify the view whenever you change something in your list..
Two options
Override ToString() method in your ProblemData type
public class ProblemData
{
//whatever...
public override string ToString()
{
return string.format("{0}", this.SomeObject); //set proper display
}
}
public class YourClass()
{
//...
public ProblemData ProblemData{ get; set;}
}
Or you can set grid column formatter if object type can be formatted using string.Format
dataGridView3.Columns["ProblemData"].DefaultCellStyle.Format = "N";
//display string.Format({0:N}

Get a value based on defined order

I currently have data in db table as follows:
Data in table
Desc Value
BNo 12
CNo Null
ANo 15
DNo Null
ENo 15
If ANo is blank i need to display BNo. If BNo is blank then display CNo on form. Once i found a non null value based on a defined priority order of DESC(In this case A-E), i need to exit my method. How can this be implemented,i can hard code desc names based on priority but it am looking to implement in a more optimized way. Any advices please.
SQL Server
select top 1 *
from MyTable
where Value is not null
order by [Desc]
MySQL:
select *
from MyTable
where `Value` is not null
order by `Desc`
limit 1
It sounds like you have the means to order the list, as you state "in a priority order". Not sure what this priority is but for the example let's assume it is in alphabetical order by "Desc". And let's also assume (for simplicity) that these values are in a dictionary. Given this you can write a Linq statement as such...
dict.OrderBy(o => o.Key).FirstOrDefault(d => d != null);
eg...
Dictionary<string,string> dict = new Dictionary<string,string>();
dict.Add("BNo", "12");
dict.Add("CNo", null);
dict.Add("ANo", null);
dict.Add("DNo", null);
dict.Add("ENo", "16");
Debug.WriteLine(dict.OrderBy(o => o.Key).FirstOrDefault(d => d.Value != null));
This will return the first non-null value. If all values are null then null is returned.
There may be some incorrect assumptions here but the OrderBy and FirstOrDefault should be able to be used in whatever manner necessary to achieve your goal. The only things that should need to change is the "o.Key" and "d.Value" to reference your actual properties.
For example, if this information is in a class such as this...
class Info
{
public string Desc { get; set; }
public int? Number { get; set; }
}
and you have a list of these such as...
List<Info> info = new List<Info>();
then you could write...
var returnValue = info.OrderBy(o => o.Desc).FirstOrDefault(d => d.Number.HasValue);
Are ANo, BNo, CNo, etc values of the Desc field in the table, or are Desc, ANo, BNo.. etc fields in the table. I get this doubt because you just that these are actually contact details.
If it is the first, RedFilter gave you an answer.
If it is the second, a dynamic query can be an option.
Just add the fields in the order of priority to an array, and iterate to build the query.

How to setup a property from 1 linq2sql obj that is populated by a relationship to another obj

I'm using Linq2SQL and I'm pretty new to it.
I've got a User table and a UserData table, the idea being that properties for the User object can be added / removed by adding or removing rows in the UserData table. I did not come up with this particular design but I am more or less stuck with it (as long as I can come up with a solution)
alt text http://www.86th.org/linq2sqlproblem.jpg
I'd like to populate/bind "FirstName" on the User object by something along the lines of setting the value to:
UserData.Value WHERE UserData.ItemID == User.UserID AND KeyName = 'FirstName'
Similarly, LastName would be:
UserData.Value WHERE UserData.ItemID == User.UserID AND KeyName = 'LastName'
Description of the UserData Table:
UserData.ItemID is the FK (User.UserID)
UserData.KeyName is specifying the name of the property
UserData.Value is the actual value.
How would I setup my User object to handle this so I could do the normal CRUD functionality on this object and have the changes carry through to both tables?
Is this even possible?
Is this bad form?
Personally I feel its bad form but I suppose everyone has there way of doing things. Why can't you assign userdata in the users table? I think I might not be understanding the design idea here.
Quick Note
I renamed UserData to ExtendedProperty and this caused the relationship from User to ExtendedProperty to be called ExtendedProperties.
Summary of changes
Created a getter/setter for both FirstName and LastName in the partial User class
Grabbed the correct ExtendedProperty element out of the ExtendedProperties collection and either returned or updated the Value property of it.
Refactored into a reusable format as shown below
partial class User
{
public string FirstName
{
get { return (string)this.getExtendedProperty("FirstName").Value; }
set { this.getExtendedProperty("FirstName").Value = value; }
}
public string LastName
{
get { return (string)this.getExtendedProperty("LastName").Value; }
set { this.getExtendedProperty("LastName").Value = value; }
}
// Grab a related property out of the collection, any changes to it will be reflected in the database after a submit
private ExtendedProperty getExtendedProperty(string KeyName)
{
// grab the properties that fit the criterea
var properties = (from prop in this.ExtendedProperties where prop.KeyName == KeyName select prop);
// return value
ExtendedProperty property = properties.SingleOrDefault();
// if this is a new user then there arent going to be any properties that match
if (property == null)
{
// Define a new item to add to the collection
property = new ExtendedProperty()
{
ItemID = this.UserID,
KeyName = KeyName,
Value = String.Empty
};
// Add the item we're about to return to the collection
this.ExtendedProperties.Add(property);
}
// either way we have a valid property to return at this point
return property;
}
}
I just hope this isn't bloated / grossly inefficient.
Edit
In getExtendedProperty, it would error when setting the FirstName or LastName of a newly created User because it would not have any corresponding ExtendedProperty elements in the ExtendedProperties collection as shown below.
User expected = new User();
expected.UserID = Guid.NewGuid();
expected.UserName = "LJ";
expected.FirstName = "Leeroy"; // It would error here
expected.LastName = "Jenkins";
Because of this I added a check to ensure that new items get added to the ExtendedProperties collection if they are requested and not currently in there.
I also removed setExtendedProperty since I felt it wasn't necessary and was just a method around a 1 liner anyway.
I would really appreciate any feedback before I accept this answer, I'll let it sit for a few days.

Categories