Add null values to a datagridview - c#

In my C# application I have a datagridview with 'person' data in it that means the datasource of this datagrisview is set with an IList of the class person.
My person model consists of the following fields (just the model, not the datagridview):
string foreName
string surname
int devisionId
int someOtherId
Organisation orga
Organisation is another model which is mapped as one-to-many with NHibernate. Among others organisation consists of the string:
string orgaName
Now comes the tricky part (for me)....
In my datagridview I dont want to have all fields of person, I just want to have the following:
foreName
surname
orga.orgaName
Getting the first twoe fields is easy:
dataGridView.DataSource = listOfPersons.Select(x => new { ForeName = x.ForeName, SurName = x.Surname}).ToList();
This works fine so far but now I also want to have the name of the organisation within my datagridview so I tried this:
dataGridView.DataSource = listOfPersons.Select(x => new { ForeName = x.ForeName, SurName = x.Surname, OrganisationName = x.Organisation.organName}).ToList();
This would also work fine if every person has an organisation, but thats not the fact. Some persons do not have an organisation so 'Organisation' is null and trying to grab Organisation.organName ends with a nullpointerexeption.
The question now is:
How can I write my select-statement for the datagridview-datasource so that the organisation name is shown when Organisation is not null, otherwisesomething else is printed to the datagridview (for example: no organisation available)

dataGridView.DataSource = listOfPersons.Select(x => new { ForeName = x.ForeName, SurName = x.Surname, OrganisationName = x.Organisation == null ? "None" : x.Organisation.organName}).ToList();

Try this :
dataGridView.DataSource = listOfPersons.Select(x => new { ForeName = x.ForeName, SurName = x.Surname, OrganisationName = x.Organisation != null ? x.Organisation.organName : "No organisation available"}).ToList();

Related

Trying to .add to a list while already fill a list?

I had this question posted with too little details and I deleted it to make it more clear here, its likely that isnt possible but I want to learn if it is, and didnt find anything about it online.
I got a class called (Student)
And in the controller a Listof(Student) and I am filling the data from SQL server
My code is
public class Student
{
public string StudentName { get; set; }
public int StudentId { get; set; }
public List<int> SubjectID { get; set; }
}
//going back to the controller and what I am trying to do
List<Student> students = new List<Student>();
Connection.open();
//the command doesnt matter but I am reading data from it that has ID Name Age and SubjectID
while (reader.Read())
{
students.Add(new Student()
{
StudentId = reader.GetInt32(0),
StudentName = reader.GetString(1),
//Here I want to fill the StudentID list, I will start typing outside of the code space
});
}
I hope the general idea is clear, I want (if possible?) to fill the StudentID list with what I get from SQL there, but since I already have the command ".add" there I cant use it inside it, also not sure if its possible to put an if statement, if the student is repeated start filling the student ID with one object inside the main list to look like this Students[0]={ Id= 1, name= Zaid, SubjectID= {1,2,3..}
I hope this made everything clear, again I know there is other ways to solve this without having to fill a list inside it but I want to know if its possible
I'll try to do that without changing your code too much.
List<Student> students = new List<Student>();
Connection.open();
Student currentStudent = null;
while (reader.Read())
{
// First, I read all the info
int id = reader.GetInt32(0);
string name = reader.GetString(1);
int subject = reader.GetString(3); // I guess the subjectID is at this index based on your post
// If it's the first record of this student, I create its instance
if (currentStudent?.StudentId != id)
{
// I add the previous student to the list
if (currentStudent != null)
{
students.Add(currentStudent);
}
currentStudent = new Student()
{
StudentId = id,
StudentName = name,
SubjectID = new List<int>() // I create an empty list for the subjects
};
}
// I add the subject to the list for this student
currentStudent.SubjectID.Add(subject);
}
This should give you the result you are expecting. It can be optimized and refactored, but it's something similar to what you already wrote. Let me know if it works correctly, I didn't run it.
You can do it with SQL side, what, i think, much better, data must be deliver to you in the way u need, without any other stuff or minimal.
SELECT st.StudentName, st.StudentId , STRING_AGG (sub.Id, ',') as
subjects
FROM Student st JOIN
Subject sub on s.SubjectId = sub.Id
GROUP BY S.Id, st.StudentName, st.StudentId
So, code must look like this
students.Add(new Student()
{
StudentId = reader.GetInt32(0),
StudentName = reader.GetString(1),
StudentId = reader.GetString(2).Split(',').Select(int.Parse).ToList()
});

add two entry for every row - Linq C#

it is my query:
from customer in db.tblCustomers
select new
{
ID = customer.CustomerID,
Mobile = customer.Mobile1,
LastName = customer.Family
};
for every customer there is tow mobile phones, I need to add a new entry if the second mobile phone is not null. also I should change the LastName for second entry to something like "Second Mobile". How can I get two different entry from one customer using linq query?
Using the same generated type you can't have one with only one property of phone number and another with two. You can do:
from customer in db.tblCustomers
select new
{
ID = customer.CustomerID,
Mobile = customer.Mobile1,
SecondMobile = customer.Mobile2, // will be null if no second mobile exists
LastName = customer.Family
};
Otherwise what you can do is create a custom type Customer that will have a single phone number and a derived type ExtendedCustomer with two - and just instantiate the one or the other. Something along the psudo:
from customer in db.tblCustomers
select customer.Mobile2 != null ? new Customer(...) : new ExtendedCustomer(...);
If what you mean is having two different objects in the resulted collection then use union:
List<Customer> result = new List<Customer>();
foreach(var item in db.tblCustomers)
{
result.Add(new Customer(/*data for first mobile phone*/);
if(item.Mobile2 != null)
{
result.Add(new Customer(/*data for second mobile phone*/);
}
}
Could you please try this if it helps?
var customers = db.tblCustomers.SelectMany(x => x.GetMultipleRow()).ToList();
GetMultipleRow is an extension method as below.
public static class CustomerExtensions
{
public static IEnumerable<Customer> GetMultipleRow(this Customer cust)
{
yield return new Customer { CustomerID = cust.CustomerID, Mobile1 = cust.Mobile1, Family = cust.Family };
/* Data for first mobile*/
if (cust.Mobile2 != null)
yield return new Customer { CustomerID = cust.CustomerID, Mobile1 = cust.Mobile2, Family = cust.Family };
/* Data for second mobile*/
}
}

Load multiple lists in to one datatable

Hi I have two lists one is parent list and other one is child list And I need to load the data contain in both list to single Datatable is there are way to do that
public class Country
{
string Name;
string Countrycode
list<Company> Companies=new list<Company>();
}
public class Company
{
string ComapnyName;
string Address1;
string Address2;
String Owner;
}
when creating table it must be like this
Name Countrycode ComapnyName Address1 Address2 Owner
USA 001 Apple Whereever null Jobbs
Japan 002 Sony Whereever null unknown
What's the problem? You can use a loop:
DataTable tblCountries = new DataTable();
// add all columns ...
foreach(Country c in allCountries)
{
if(c.Companies.Any())
{
foreach(var company in c.Companies)
{
var row = tblCountries.Rows.Add();
row.SetField("Name", c.Name);
row.SetField("Countrycode", c.Countrycode);
row.SetField("CompanyName", company.CompanyName);
// add the other company fields ...
}
}
else // add just the country and let the company cells be null
{
var row = tblCountries.Rows.Add();
row.SetField("Name", c.Name);
row.SetField("Countrycode", c.Countrycode);
}
}
You probably want to use microsofts example of how to create a copy to datable method show here MSDN
You can then do the following
Country.SelectMany(x => x.Companies
.Select(y => new {
x.Name,
x.CountryCode,
y.ComapnyName,
y.Address1,
y.Address2,
y.Owner
} )).CopyToDataTable();
PS copied the spelling of Comapny name not sure if you mean this!
Update to deal with Companies being null
If the companies property could be null:
Country.SelectMany(x => (x.Companies ?? Enumerable.Empty<Company>())
.Select(y => new {
x.Name,
x.CountryCode,
y.ComapnyName,
y.Address1,
y.Address2,
y.Owner
} )).CopyToDataTable();

GridView DataKeyNames of nested collections or custom object

I'm using custom objects to bind to a GridView.
Suppose I have a collection of Car Companies (Audi, Ford, BMW, etc). Each Company object has properties like Id, Name, Country, etc.
Each Company also has a Collection of Cars. Each Car has properties like Id, Model, Year, etc.
I want to bind this info to a GridView.
So I'm retrieving a query of Companies and in first object of each Cars Collection, has data of one car (the object model is like this because in other scenarios I have to list all the cars of a Company).
There is no problem when I bind the Gridview to the Companies collection. I can list each company and each car info I want to show.
The problem arises when I want to set the DataKeyNames. I want to set it with the Id of each Car (not the Id of each company) for comparing cars.
I was trying something like this:
GridViewCompanies.DataSource = companies;
GridViewCompanies.DataKeyNames = new string[] { "Cars[0].Id" };
But it does not work, it says it does not contain a property with the name.
Is there any way to set it?
I don't want to bind the Gridview to a Cars collection instead because if I do it that way, I would miss the info of each Company and I need to use company's properties too.
Many thanks.
Try it:
var carCompanyList = new[]
{
new { Id = 1, Name = "Audi", Cars = new[] { new { Id = 10, Model = "Audi_Model_1" }, new { Id = 12, Model = "Audi_Model_2" } } },
new { Id = 2, Name = "Ford", Cars = new[] { new { Id = 20, Model = "Ford_Model_1" }, new { Id = 22, Model = "Ford_Model_2" } } }
};
var gridViewData = from carCompany in carCompanyList
select new
{
carCompany.Id,
carCompany.Name,
firstModelId = carCompany.Cars == null || carCompany.Cars.Count() == 0 ? 0 : carCompany.Cars.First().Id
};
CarModelGridView.DataSource = gridViewData;
CarModelGridView.DataKeyNames = new [] { "firstModelId" };
CarModelGridView.DataBind();

Concatenate Two Fields to Display in Dropdown List

I am trying to concatenate two fields from a list to display in a dropdown.
Below is the code i am trying to use. I don't want to change the model of my products so I was trying to do something like that below but I can't figure anything out without building out my own object with the fields concatenated.
skuDropDown.DataSource = List<product>
skuDropDown.DataTextField = "ProductId" // want to combine with"Description";
skuDropDown.DataValueField = "ProductId";
skuDropDown.DataBind();
Thanks any ideas will help.
To assign the source with your given method, I would go for using LINQ to create an anonymous type with the properties you want. Something like
List<Product> products = new List<Product>();
products.Add(new Product() { ProductId = 1, Description = "Foo" });
products.Add(new Product() { ProductId = 2, Description = "Bar" });
var productQuery = products.Select(p => new { ProductId = p.ProductId, DisplayText = p.ProductId.ToString() + " " + p.Description });
skuDropDown.DataSource = productQuery;
skuDropDown.DataValueField = "ProductId";
skuDropDown.DataTextField = "DisplayText";
skuDropDown.DataBind();
IF you have a class to represent a product, just create a property that extend your class and return it combined, for example:
public string ID_Description {
get
{
return string.Format("{0} ({1})", Name, ProductId);
}
}
and, in your databind dropdown reference your property
skuDropDown.DataSource = productQuery;
skuDropDown.DataValueField = "ProductId";
skuDropDown.DataTextField = "ID_Description";
skuDropDown.DataBind();
You can do this:
List<Product>.ForEach(
x => skuDropDown.Items.Add(
new Item(x.ProductId + " " x.ProductDescription, x.ProductId)
);
Just loop through the list and add each item to the drop down list. It's what .net will do for you behind the scenes in your example.
Create a new class which extends the product, cast the List contents as the extended class, which contains a new property, which returns the concatenated values of ProductID and Description.
I think that should work OTOMH.
I know that you don't want to change the products structure, which is why I suggested making an extended class. But afaik it's not possible without binding it to a field of the object.
Unfortunately, if you're using databinding, the DataTextField must be the name of a field on your data source.
One thing you can do is iterate the items in the dropdownlist after you've bound them and modify their Text properties. The only other thing to do is get the concatenated field added to the data object.
All you need to do is override the .ToString() method of the Product.
public override string ToString()
{
return ProductID + " " + ProductDescription;
}
Then all you need to do is bind to the drop down. From my understanding, the dropdown lables ar bound to the tostring() of the objects in the collection it's bound to.
in other words, do this.
List<Product> products = new List<Product>();
products.Add(new Product() { ProductId = 1, Description = "Foo" });
products.Add(new Product() { ProductId = 2, Description = "Bar" });
var productQuery = products.Select(p => new { ProductId = p.ProductId, DisplayText = p.ProductId.ToString() + " " + p.Description });
skuDropDown.DataSource = productQuery;
skuDropDown.DataBind();

Categories

Resources