LinQ Count based on element in child class - c#

I have a JSON class which I used to deserialize my object to :-
public class Response
{
private Meta _meta;
private Result _result;
private Output _output;
public Meta meta
{
set
{
if (this._meta == null)
{
this._meta = new Meta();
}
this._meta = value;
}
get
{
return this._meta;
}
}
public Output output
{
set
{
if (this._output == null)
{
this._output = new Output();
}
this._output = value;
}
get
{
return this._output;
}
}
}
Which inherit
public class Output
{
...
public Verified verified{
get
{
return this._verified;
}
set
{
if (this._verified == null)
{
this._verified = new Verified();
}
this._verified = value;
}
}
in which has sub class of
public class Verified
{
...
public Address Address
{
set
{
if (this.address == null)
{
this.address = new Address();
}
this.address = value;
}
get
{
return this.address;
}
}
public Age Age
{
get
{
return this.age;
}
set
{
if (this.age == null)
{
this.age = new Age();
}
this.age = value;
}
}
public City City
{
get
{
return this.city;
}
set
{
if (this.city == null)
{
this.city = new City();
}
this.city = value;
}
}
...
All the attribute in City, Age, and Address are the same such as
public class Address
{
public int code { get; set; }
public string text { get; set; }
}
I have manage to count how many attribute in the Verified by using
TotalQuestion = response.output.verified.GetType().GetProperties()
.Where(p => !p.PropertyType.IsGenericType
&& !p.PropertyType.IsArray)
.Count();
, and that is only half of my concern. I have to also count now many of the attribute "code" in each of the class in Address, City, Age which has value as 3.
I did tried to add .GetType().GetProperty("code") at the back of the same LinQ I used to query the total amount of question inside, but I got lost in mind how to complete it.
I hope that anyone would be able to advice on possible LinQ solution (hopefully one-liner) type.
Thanks.
Simon

I think this is what you are looking for -
var result = resp.output.verified.GetType().GetProperties().Where(
child => {
var prop = child.GetValue(resp.output.verified, null);
return (int)prop.GetType().GetProperty("code").GetValue(prop, null) == 3;
}).ToList();

Related

How can I fix the issue with the input string in this cmdlet?

In the last month of so I have been trying to learn some C# with the aim of writing some PowerShell modules. I looked at some articles and documentation (Creating a client with C# - Microsoft.Management.Infrastructure) to try and put together a simple CIM cmdlet that would return the local network adapters.
The class library compiles okay, but when I run the command in PowerShell, it shows a format exception.
Show-LocalAdapter : Input string was not in a correct format.
In function based problems, I would normally see an issue with a line in the error reporting, but the error does not point me in the right direction with a cmdlet.
Hopefully someone here can help me as I have exhausted my, admittedly limited, knowledge on debugging this problem.
Here is the code for the cmdlet.
using System.Collections;
using System.Linq;
using System.Management.Automation;
using System.Text.RegularExpressions;
using Microsoft.Management.Infrastructure;
namespace NetTest
{
[Cmdlet(VerbsCommon.Show, "LocalAdapter")]
[OutputType(typeof(NetworkAdapter))]
public class ShowLocalAdapterCmdlet : PSCmdlet
{
private string[] _manufacturer;
private string _name;
private bool? _physicalAdapter;
private int _maxEntries = 100;
[Parameter(Position = 0, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true)]
[Alias("Vendor")]
public string[] Manufacturer
{
get { return this._manufacturer; }
set { _manufacturer = value; }
}
[Parameter(Position = 1, ValueFromPipelineByPropertyName = true)]
public string Name
{
get { return this._name; }
set { _name = value; }
}
[Parameter(Position = 2, ValueFromPipelineByPropertyName = true)]
public bool? PhysicalAdapter
{
get { return this._physicalAdapter; }
set { _physicalAdapter = value; }
}
[Parameter(Position = 3)]
public int MaxEntries
{
get { return this._maxEntries; }
set { _maxEntries = value; }
}
protected override void BeginProcessing()
{
base.BeginProcessing();
}
protected override void ProcessRecord()
{
CimSession session = CimSession.Create("localHost");
IEnumerable cimResults = session.QueryInstances(#"root\cimv2", "WQL", "SELECT * FROM Win32_NetworkAdapter");
var query = cimResults.Cast<CimInstance>().Select(ReturnNetworkAdapter);
// Filter Name
if (Name != null)
{
query = query.Where(adapter => adapter.Name != null && adapter.Name.StartsWith(Name));
}
// Manufacturer Filter
if (Manufacturer != null)
{
query = query.Where(
adapter =>
adapter.Manufacturer != null &&
Regex.IsMatch(adapter.Manufacturer.ToString(),
string.Format("^(?:{0})", string.Join("|", Manufacturer))));
}
// Physical Adapter: true or false
if (PhysicalAdapter != null)
{
query = query.Where(adapter =>
adapter.PhysicalAdapter == PhysicalAdapter);
}
// Return objects
query.Take(MaxEntries).ToList().ForEach(WriteObject);
}
private static NetworkAdapter ReturnNetworkAdapter(CimInstance item)
{
return new NetworkAdapter
{
Name = item.CimInstanceProperties["Name"].ToString(),
Description = item.CimInstanceProperties["Description"].ToString(),
DeviceId = int.Parse(item.CimInstanceProperties["DeviceId"].ToString()),
Manufacturer = item.CimInstanceProperties["Manufacturer"].ToString(),
NetConnectionId = item.CimInstanceProperties["NetConnectionId"].ToString(),
PhysicalAdapter = bool.Parse(item.CimInstanceProperties["PhysicalAdapter"].ToString())
};
}
}
}
Here is the class for the network adapter object.
namespace NetTest
{
public class NetworkAdapter
{
private string _name;
private string _description;
private int _deviceId;
private string _manufacturer;
private string _netConnectionId;
private bool _physicalAdapter;
public string Name
{
get { return _name; }
set { _name = value; }
}
public string Description
{
get { return _description; }
set { _description = value; }
}
public int DeviceId
{
get { return _deviceId; }
set { _deviceId = value; }
}
public string Manufacturer
{
get { return _manufacturer; }
set { _manufacturer = value; }
}
public string NetConnectionId
{
get { return _netConnectionId; }
set { _netConnectionId = value; }
}
public bool PhysicalAdapter
{
get { return _physicalAdapter; }
set { _physicalAdapter = value; }
}
}
}
Calls like this item.CimInstanceProperties["Name"].ToString() is not what are you expecting. You should look at property Value:
private static NetworkAdapter ReturnNetworkAdapter(CimInstance item)
{
return new NetworkAdapter
{
Name = item.CimInstanceProperties["Name"].Value.ToString(),
Description = item.CimInstanceProperties["Description"].Value?.ToString(),
DeviceId = int.Parse(item.CimInstanceProperties["DeviceId"].Value.ToString()),
Manufacturer = item.CimInstanceProperties["Manufacturer"].Value?.ToString(),
NetConnectionId = item.CimInstanceProperties["NetConnectionId"].Value?.ToString(),
PhysicalAdapter = bool.Parse(item.CimInstanceProperties["PhysicalAdapter"].Value.ToString())
};
}

Custom Collection/List To Store Custom Objects

I have a customer object class:
public class customerObject
{
private string _address1;
private string _address2;
private string _address3;
private string _category;
private string _country;
private string _county;
private string _custcode;
private string _fullname;
private string _int_rep_hou;
private string _int_rep_key;
private double _lat;
private double _lng;
private string _postcode;
private string _rep_code;
private string _telephone;
public customerObject()
{
}
public string Address1
{
get { return _address1; }
set { _address1 = value; }
}
public string Address2
{
get
{
return _address2;
}
set { _address2 = value; }
}
public string Address3 { get { return _address3; } set { _address3 = value; } }
public string Category
{
get { return _category; }
set { _category = value; }
}
public string Country { get { return _country; } set { _country = value; } }
public string County { get { return _county; } set { _county = value; } }
public string Custcode
{
get { return _custcode; }
set { _custcode = value; }
}
public string Fullname
{
get { return _fullname; }
set { _fullname = value; }
}
public string Int_rep_hou
{
get { return _int_rep_hou; }
set { _int_rep_hou = value; }
}
public string Int_rep_key
{
get { return _int_rep_key; }
set { _int_rep_key = value; }
}
public double Lat { get { return _lat; } set { _lat = value; } }
public double Lng { get { return _lng; } set { _lng = value; } }
public string Postcode { get { return _postcode; } set { _postcode = value; } }
public string Rep_code
{
get { return _rep_code; }
set { Rep_code = value; }
}
public string Telephone { get { return _telephone; } set { _telephone = value; }
}
}
I have a CustomCollections class
public class CustomerCollection
{
public List<customerObject> Customers { get; set; }
}
My method that loops through dt rows and converts to a customer object
public List<Valueobjects.CustomerCollection> dolist(DataTable temptablename)
{
//Create Collection Object
Valueobjects.CustomerCollection Collection = new Valueobjects.CustomerCollection();
foreach (DataRow row in temptablename.Rows)
{
//Create Customer Object
Valueobjects.customerObject Customer = new Valueobjects.customerObject();
//set values of customer object
Customer.Rep_code = "";
Customer.Int_rep_key = "";
Customer.Int_rep_hou = "";
Customer.Fullname = row["Fullname"].ToString().Trim();
Customer.Custcode = row["Custcode"].ToString().Trim();
Customer.Category = row["Category"].ToString().Trim();
Customer.Address1 = row["Address1"].ToString().Trim();
Customer.Address2 = row["Address2"].ToString().Trim();
Customer.Address3 = row["Address3"].ToString().Trim();
Customer.Postcode = row["Postcode"].ToString().Trim();
Customer.Country = row["Country"].ToString().Trim();
Customer.Telephone = row["Telephone"].ToString().Trim();
Customer.Lat = Convert.ToDouble(row["Lat"]);
Customer.Lng = Convert.ToDouble(row["Lng"]);
Customer.County = row["County"].ToString().Trim();
//add to the collection (list)
Collection.Customers.Add(Customer);
}
temptablename = null;
return Collection;
}
However when I create a new Customer object and a new CustomerCollection object I am getting an error when adding the customer to the collection list.
Error:
Error 32 Cannot implicitly convert type
'Classes.Valueobjects.CustomerCollection' to
'System.Collections.Generic.List'
Your method is returning a List<CustomerCollection>:
public List<Valueobjects.CustomerCollection> dolist(DataTable temptablename)
{
//...
}
But the code is trying to return a CustomerCollection:
return Collection;
Just as the error says, these two types are different.
If a CustomerCollection is already a collection of customers, then semantically what is a List<Valueobjects.CustomerCollection>? A collection of collections? It seems like you're over-pluralizing your objects :)
There are two approaches here. Either return a CustomerCollection from the method:
public CustomerCollection dolist(DataTable temptablename)
{
//...
}
Or use a List<Customer> if you want to use generic lists as your collection containers:
public List<Customer> dolist(DataTable temptablename)
{
//...
var Collection = new List<Customer>();
//...
Collection.Add(Customer);
//...
return Collection;
}
Side note: You may want to stick to C# conventions for variable naming. As you can see from the code highlighting here on Stack Overflow, your variable names can easily be mistaken for classes/types, which can cause confusion when supporting the code.
Return a CustomerCollection instead of a List<Valueobjects.CustomerCollection>:
public Valueobjects.CustomerCollection Dolist(DataTable temptablename)
{
// ...
Your object has a list, it is not a list.
MSDN: Inheritance

How to convert DataTable to List<T> while watching for nulls

Movie Class
public class Movie
{
#region Properties
public string Name { get { return _name; } set { _name = value; } }
public string Producer { get { return _producer; } set { _producer = value; } }
public int Rating { get { return _rating; } }
public Image Covor { get; set; }
public string Description { get { return _description; } }
public int ReleaseYear { get { return _releaseYear; } set { _releaseYear = value; }}
#endregion
#region Private Fields
private string _name;
private string _producer;
private int _rating;
private string _description;
private int _releaseYear;
#endregion
#region Constructors
public Movie()
{
}
public Movie(string name, int yearRelease)
{
this._name = name;
this._releaseYear = yearRelease;
}
public Movie(string name, int yearRelease, string producer)
{
this._name = name;
this._releaseYear = yearRelease;
this._producer = producer;
}
#endregion
}
My attempt
foreach (DataRow movieRow in MovieTable().AsEnumerable())
{
if (movieRow["Producer"] != DBNull.Value)
{
Movie movie = new Movie()
{
Name = (string)movieRow["Name"],
Producer = (string)movieRow["Producer"],
ReleaseYear = (int)movieRow["Release Year"]
};
movieList.Add(movie);
}
else
{
Movie movie = new Movie()
{
Name = (string)movieRow["Name"],
ReleaseYear = (int)movieRow["Release Year"]
};
movieList.Add(movie);
}
}
This is my code so far I'm trying to convert a Table to a List. The only problem is DBNull's.
I would like to update the entire table to a list, this works currently for 2 situations, but I need for the List to contain all the information if it exists. I could create elseif statements to handle every possible scenario but there has to be a way better way to figure out if the type is DBNull and if not set the property correctly.
If there's any confusion tell me what it is and I'll explain further.
One option is to incorporate the null-check into the set-statements wherever you need them, using shorthand code:
Name = (movieRow["Name"] == DBNull.Value) ?
(string)movieRow["Name"] :
string.Empty,
// Producer will be given a value if it exists, or null otherwise:
Producer = (movieRow["Producer"] == DBNull.Value) ?
(string) movieRow["Producer"] :
null,
...
You can replace string.Empty with null or vice versa of course, if that suits you better.
Edit: Just a very basic clarification, since you state you are new to programming: This shorthand notation means "if firstValue is true, return secondValue, otherwise, return thirdValue"
var result = firstValue ? secondValue : thirdValue;
One option: you can check IsNull(column):
Movie movie = new Movie()
{
Name = movieRow.IsNull("Name")
? (string)null : (string)movieRow["Name"],
Producer = movieRow.IsNull("Producer")
? (string)null : (string)movieRow["Producer"],
// etc..
};
movieList.Add(movie);

LINQ using shared object

I have a table (called !test) containing the following data:
id code desc
0 55 fifty-five
1 66 sixty-six
2 100 hundred
When I use the following code to access that table, it compiles & runs OK,
but doesn't populate the Tuple structure.
[global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.!test")]
public partial class Test
{
private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty);
private int _ID;
private TupleClass _Tuple;
public Test()
{
_Tuple = new TupleClass();
}
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_ID", DbType="Int NOT NULL", IsPrimaryKey=true)]
public int ID
{
get
{
return this._ID;
}
set
{
if ((this._ID != value))
{
this._ID = value;
}
}
}
public TupleClass Tuple
{
get
{
return this._Tuple;
}
set
{
if ((this._Tuple.Code != value.Code))
{
this._Tuple.Code = value.Code;
}
if ((this._Tuple.Desc != value.Desc))
{
this._Tuple.Desc = value.Desc;
}
}
}
}
public class TupleClass
{
private int _Code;
private string _Desc;
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage = "_Code", DbType = "Int NOT NULL")]
public int Code
{
get
{
return this._Code;
}
set
{
if ((this._Code != value))
{
this._Code = value;
}
}
}
[global::System.Data.Linq.Mapping.ColumnAttribute(Storage = "_Desc", DbType = "NVarChar(50)")]
public string Desc
{
get
{
return this._Desc;
}
set
{
if ((this._Desc != value))
{
this._Desc = value;
}
}
}
}
Any ideas what I've done wrong here? Thanks

Errors: How to save a many-to-many relationship in Castle Active Record?

I've been trying for hours to get many-to-many relationship to save with Castle ActiveRecord. What am I doing wrong? I can't find anything in the documentation or on google. There is data in the database.
Courses have a many to many relationship with Books.
Test code.
Database.Course c = new Database.Course();
c.Number = "CS 433";
c.Name = "Databases";
c.Size = 34;
c.Books = Database.Book.FindAll();
c.Save();
Also doesn't work
foreach(Database.Book b in Database.Book.FindAll()){
c.Books.Add(b);
}
Database Classes
[ActiveRecord]
public class Course : ActiveRecordValidationBase<Course>
{
private int? id;
private string number;
private string name;
private string description;
private int size; //number of students in class
//references
private IList books = new ArrayList();
public override string ToString()
{
return FormattedName;
}
public string FormattedName
{
get
{
return string.Format("{0} - {1}", Number, Name);
}
}
[PrimaryKey]
public int? Id
{
get { return id; }
set { id = value; }
}
[Property, ValidateNonEmpty]
public string Number
{
get { return number; }
set { number = value; }
}
[Property, ValidateNonEmpty]
public string Name
{
get { return name; }
set { name = value; }
}
[Property(ColumnType="StringClob")]
public string Description
{
get { return description; }
set { description = value; }
}
[Property]
public int Size
{
get { return size; }
set { size = value; }
}
[HasAndBelongsToMany(typeof(Book),
Table = "BookCourse", ColumnKey = "course_id", ColumnRef = "book_id", Inverse = true)]
public IList Books
{
get { return books; }
set { books = value; }
}
}
[ActiveRecord]
public class Book : ActiveRecordValidationBase<Book>
{
private int? id;
private string title;
private string edition;
private string isbn;
private bool is_available_for_order;
//relations
private IList authors = new ArrayList();
private IList bookordercount = new ArrayList();
private IList courses = new ArrayList();
private Inventory inventory;
public override string ToString()
{
return FormattedName;
}
public string FormattedName
{
//*
get {
string str;
if (Edition == null || Edition == "")
str = Title;
else
str = string.Format("{0} ({1})", Title, Edition);
if (Authors.Count != 0)
{
return string.Format("{0} by {1}", str, FormattedAuthors);
}
else
{
return str;
}
}
/*/
get
{
return Title;
}
//*/
}
public string FormattedAuthors
{
get
{
if (Authors.Count == 0) return "";
StringBuilder sb = new StringBuilder();
int i = 0, end = Authors.Count;
foreach (Author a in Authors)
{
i++;
sb.Append(a.FormattedName);
if (i != end) sb.Append("; ");
}
return sb.ToString();
}
}
[PrimaryKey]
public int? Id
{
get { return id; }
set { id = value; }
}
[Property, ValidateNonEmpty]
public string Title
{
get { return title; }
set { title = value; }
}
[Property]
public string Edition
{
get { return edition; }
set { edition = value; }
}
[Property, ValidateNonEmpty]
public string Isbn
{
get { return isbn; }
set { isbn = value; }
}
[Property]
public bool IsAvailableForOrder
{
get { return is_available_for_order; }
set { is_available_for_order = value; }
}
//relations
[HasAndBelongsToMany(typeof(Author),
Table = "BookAuthor", ColumnKey = "book_id", ColumnRef = "author_id")]
public IList Authors
{
get { return authors; }
set { authors = value; }
}
[HasMany(typeof(BookOrderCount), Table = "BookOrderCounts", ColumnKey = "BookId")]
public IList BookOrderCount
{
get { return bookordercount; }
set { bookordercount = value; }
}
[HasAndBelongsToMany(typeof(Course),
Table = "BookCourse", ColumnKey = "book_id", ColumnRef = "course_id")]
public IList Courses
{
get { return courses; }
set { courses = value; }
}
[OneToOne]
public Inventory Inventory
{
get { return inventory; }
set { inventory = value; }
}
}
Make sure you put the Inverse = true where you want it. From the Castle AR docs,
It is wise to choose one side of the
relation as the owner. The other side,
the non-writable, need to use
Inverse=true.
Put the Inverse = true on the other side of the relationship, like this:
[HasAndBelongsToMany(typeof(Book),
Table = "BookCourse", ColumnKey = "course_id", ColumnRef = "book_id")]
public IList<Book> Books
[HasAndBelongsToMany(typeof(Course),
Table = "BookCourse", ColumnKey = "book_id", ColumnRef = "course_id", Inverse = true)]
public IList<Course> Courses
You also have to add attributes to the top of both classes - at the moment they don't know what tables they're mapped to. Currently you have this:
public class Course : ActiveRecordBase<Course>
Add this (where "course" is the name of your Course table):
[ActiveRecord("course")]
public class Course : ActiveRecordBase<Course>

Categories