Organizing data in a class - c#

I have a question regarding the way I'm storing data in my application, keep in mind I'm not too experienced with C#. So, I am grabbing data from a file and able to print it all out using a foreach loops
try
{
var doc = new HtmlDocument();
doc.LoadHtml(htmlDoc);
var i = 0;
foreach (HtmlNode row in doc.DocumentNode.SelectNodes("//tr"))
{
if (i <= 6) { Console.Write("[Type1]"); }
if (i >= 7 && i <= 12) { Console.Write("[Type2 i + " : "); }
if (i >= 13 && i <= 23) { Console.Write("[Type3] i + " : "); }
if (i >= 24 && i <= 33) { Console.Write("[Type4]" + i + " : "); }
if (i >= 34 && i <= 39) { Console.Write("[Type5]" + i + " : "); }
if (i > 38 || i < 1) { Console.Write("Error LTZ or GTV"); }
Console.Write(row.Elements("td").First().InnerText);
Console.Write(" - ");
Console.WriteLine(row.Elements("td").Last().InnerText);
i++;
}
}
This part works fine, it prints them all out with the appropriate tag in front of the data. What I am trying to accomplish is instead of printing the data out I want to store it in my class. I have it modeled like this currently
public class House
{
//Downstairs
public int DBedrooms {get; set; }
public int DKitchens {get; set; }
public int DLiving { get; set; }
//upstairs
public int UBedrooms { get; set; }
public int UKitchens { get; set; }
public int ULiving { get; set; }
//Neighborhood
public string NSchool { get; set; }
public int NSchoolDist { get; set; }
public int NCrime { get; set; }
...
...
...
}
there's about 40 public ints in the class currently and I'm just wondering what a better way to store the data would be!

Every structure that can have duplicates should have their own class instead of just declaring a lot of properties, and I personally like storing such structures in a list. you would also want to add them to the list in the right order so you don't mistake the upstairs for the downstairs.
For the ability to have many floors in a house i would organize like so:
public class Floor {
public int DBedrooms {get; set; }
public int DKitchens {get; set; }
public int DLiving { get; set; }
}
public class House {
public List<Floor> Floors{get;set;}
public string NSchool { get; set; }
public int NSchoolDist { get; set; }
public int NCrime { get; set; }
}
FYI: if you might be able to use a Repeater instead of programmably creating html (http://www.w3schools.com/aspnet/aspnet_repeater.asp), although I don't know if it fits your use case.
Edit: also if you are the one creating the source files then consider deserialization from xml.

First of all, what is the use case of the object? If it's simply a data transfer object then leaving it as it is should be fine. However if parts of the object are to be used throughout the application then you could break it down into pieces like so:
public class Downstairs : Floor
{
public IList<Room> Rooms { get; set;}
}
public class Upstairs : Floor
{
public IList<Room> Rooms { get;set; }
}
public class House
{
public HouseOwner Owner { get;set; }
public readonly IList<Floor> Floors { get; private set;}
public House(HouseOwner owner, IList<Floor> floors)
{
this.Owner = owner;
this.Floors = floors;
}
public void AddFloor(Floor floor)
{
this.Floors.Add(floor);
}
public int TotalFloors()
{
return this.Floors.Count();
}
}
By modelling your data like this each object encapsulates its own and properties data making it a little more organised than a large generalised class.

Related

C# how to check array in list

I'm building a Worker service for Windows who gets data from another program on the system.
at this point i have all data that is need now i want to keep a list with up to date data.
When i run the application for the Zones i get System.Int32[] what i would love to see is the data from System.Int32[]
how to obtain this?
List<BroadcastModel> activeOmroep = new List<BroadcastModel>();
for (int o = 0; o < webcontent.Length; o++)
{
for (int i = 0; i < webcontent[o].Zones.Length; i++)
{
}
activeOmroep.Add(new BroadcastModel
{
Id = webcontent[o].Id,
Name = webcontent[o].Name,
Recording = webcontent[o].Recording,
Zones = webcontent[o].Zones
}) ;
My BroadcastModel class looks like the following:
public class BroadcastModel
{
public int Id { get; set; }
public string Name { get; set; }
public int[] Channels { get; set; }
public bool Recording { get; set; }
public int Type { get; set; }
public int Volume { get; set; }
public int[] Zones { get; set; }
}
Thanks in advance.
for testing purpose i added the following:
foreach (var omroep in activeOmroep)
{
Console.WriteLine("Broadcast ID: " + omroep.Id);
Console.WriteLine("Broadcast Name: " + omroep.Name);
Console.WriteLine("Broadcast is recording: " + omroep.Recording);
Console.WriteLine("Broadcast Zones: " + omroep.Zones);
Console.WriteLine("****************************");
}
but then i got the system.int32[]
Whenever you are printing data using Console.WriteLine(), it calls .ToString() method, if .ToString() is not overridden then it calls Object.ToString() method. Object.ToString() prints type in the string format.
In your case Console.WriteLine("Broadcast Zones: " + omroep.Zones); is printing System.Int32[], because it is calling ToString() method with the basic behavior.
To solve your issue, I would suggest to Override ToString() method in BroadcastModel class and return string which you want to print.
To print array elements, use string.Join() method.
Concatenates the elements of a specified array or the members of a
collection, using the specified separator between each element or
member.
public class BroadcastModel
{
public int Id { get; set; }
public string Name { get; set; }
public int[] Channels { get; set; }
public bool Recording { get; set; }
public int Type { get; set; }
public int Volume { get; set; }
public int[] Zones { get; set; }
public override string ToString()
{
return $"ID : {this.Id}, \nName: {this.Name} \nIs recording: {this.Recording} \nZones : {string.Join(", ", this.Zones)}";
}
}
Now you can print List<BroadcastModel> using foreach loop,
foreach(var broadcastmodel in activeOmroep)
Console.WriteLine(broadcastmodel);

How to get list from nested list with highest length?

Below is my class structure:
public class TopLevel
{
public int Id { get; set; }
public List<ChildLevelList> ChildLevelList { get; set; }
}
public class ChildLevelList
{
public int Id { get; set; }
public List<ChildLevelList1> ChildLevelList1 { get; set; }
}
public class ChildLevelList1
{
public int Id { get; set; }
}
Now i am trying to get that ChildLevelList1 whose length is highest among all other ChildLevelList1 for each TopLevel records.If found then return that list of ChildListLevel1 for that Top level record
For eg: suppose i have records like below:
TopLevel[0]: ChildLevelList1 (Length =3)
TopLevel[1]: ChildLevelList1 (Length =4)
TopLevel[2]: ChildLevelList1 (Length =8) //get this list
TopLevel[3]: ChildLevelList1 (Length =2)
So I would like to get ChildLevelList for TopLevel 2 i.e from third position like below:
Output:[2]: ChildLevelList1 (Length =8)
I am trying to get in below variable:
var childLevelList1 // trying to get in this varaible
This is how I am trying:
for (int i = 0; i < List.Count(); i++)
{
//Sorry but not getting how to do this.
}
First of all I choose some better names to avoid confusion
public class TopLevel
{
public int Id { get; set; }
public List<ChildLevel> ChildLevelList { get; set; }
}
public class ChildLevel // was ChildLevelList
{
public int Id { get; set; }
public List<ChildLevel1> ChildLevelList1 { get; set; }
}
public class ChildLevel1 // was ChildLevel1List
{
public int Id { get; set; }
}
And to get the List with the highest length
public List<ChildLevel1> GetBiggestChildLevel1List( IEnumerable<TopLevel> source )
{
return source
.SelectMany( t => t.ChildLevelList ) // IEnumerable<ChildLevel>
.Select( c1 => c1.ChildLevelList1 ) // IEnumerable<List<ChildLevel1>>
.OrderByDescending( c2l => c2l.Count ) // IEnumerable<List<ChildLevel1>>
.FirstOrDefault();
}
You are going down two levels from TopLevel, therefore you can try with the following LINQ query:
var result = List.OrderByDescending(x => x.ChildLevelList.Select(y => y.ChildLevelList1.Count())).First();

Storing/retrieving a JSON string in the database making it easy to work with in code

I have a c# object 'Product' with a property called: Offset
In the database the field is of type nvarchar(50)
I will be storing a JSON value in it such as the following: { "y": 0, "m": 0, "d": 0 }
I would like to know a good way of working with a property like this in my code. Here is how I currently am doing it:
public class Product
{
public int Id {get; set;}
public string Description {get; set;}
public decimal Price {get; set;}
public int OffsetYears { get; set; }
public int OffsetMonths { get; set; }
public int OffsetDays { get; set; }
public string Offset
{
get
{
Offset offset = new Offset()
{
Y = OffsetYears,
M = OffsetMonths,
D = OffsetDays
};
return JsonConvert.SerializeObject(offset);
}
set
{
OffsetObj offset = JsonConvert.DeserializeObject<Offset>(value);
OffsetYears = offset.Y;
OffsetMonths = offset.M;
OffsetDays = offset.D;
}
}
private class OffsetObj
{
public int Y { get; set; }
public int M { get; set; }
public int D { get; set; }
}
}
So then when I accept values from the User in the UI I would set the OffsetYears, OffsetMonths, and OffsetDays properties.. So in my repository I can just save Offset.
And when retrieving values from the database I will simply work with OffsetYears, OffsetMonths, and OffsetDays properties in my code.
Is there a better way to handle this sort of thing? I just feel like I am not utilizing all of my c# resources. Like what if another developer accidentally sets Offset through the code assuming any format of string can go in it.
Or am I better off just creating 3 separate integer fields in the database and avoiding all of this...
I would hold the values in a field of your private type. Consider this approach:
public class Product
{
private OffsetObj _offset = new OffsetObj();
public int Id { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public int OffsetYears
{
get { return _offset.Y; }
set { _offset.Y = value; }
}
public int OffsetMonths
{
get { return _offset.M; }
set { _offset.M = value; }
}
public int OffsetDays
{
get { return _offset.D; }
set { _offset.D = value; }
}
public string Offset
{
get
{
return JsonConvert.SerializeObject(_offset);
}
set
{
_offset = JsonConvert.DeserializeObject<OffsetObj>(value);
}
}
private class OffsetObj
{
public int Y { get; set; }
public int M { get; set; }
public int D { get; set; }
}
}
This way, the field offset will hold the values for the offset.
Like what if another developer accidentally sets Offset through the code assuming any format of string can go in it.
JsonConvert will throw a JsonReaderException if trying to set the Offset property to a string that does not match JSON-format. In my opinion this is expected. To clarify further, you could name your property to OffsetJson.
However, I fail to see the benefit in this simple case to store your information as JSON. If you are using a relational database, you may as well just store your values in separate columns.

Access the data in the dictionary when the item is an object?

So I am lost on how to send data back to the object once it is added to the dictionary.
With this data structure that I made http://pastebin.com/HicZMzAt for full code
I have
public class Computer
{
public Computer() { }
public Computer(int _year)
{
dropOffDate = DateTime.Now;
RepairFinished = false;
Year = _year;
}
private DateTime dropOffDate;
public bool RepairFinished;
private readonly int Year;
public static string Plate;
private string make;
public string Make
{
get { return make; }
set { make = value; }
}
public string Model { get; set; }
public string ComputerTicketId { get; set; }
public bool IsLaptop { get; set; }
public Location Location { get; set; }
public int HoursWorked { get; set; }
public double PartsCost { get; set; }
public DateTime DateFinished { get; set; }
// public virtual double TotalCost { get { TotalCost = (this.HoursWorked * 50) + PartsCost; } set; }
public void ComputerPickUp()
{
Console.WriteLine("Cost is {0:C} ", this.HoursWorked);
RepairFinished = true;
}
where I want to calculate the different cost for repairs for each dropped of system.
public class Laptop : Computer
{
public bool HasCharger { get; set; }
public Laptop(int year, bool _HasCharger)
: base(year)
{
HasCharger = _HasCharger;
}
//TODO overide for COST ! + 10
and I have a desktop class also were the cost of repair is cheaper for Desktop systems.
But I am using
public static class Repair
{
public static Dictionary<string, object> RepairLog { get; set; }
}
to track the repairs
and now I am lost in the UI part of the program to get the data to figure out the pricing.
public class RepairUI
{
....edited
Repair.RepairLog = new Dictionary<string, object>();
....
Computer = new Desktop(ComputerYear, HasLcd);
And that is how I am lost about the way to handle the data , the class data for each repair unit (desktop / NBK ) is organized in the dictionary and now I want to get the data and edit the repair cost of the object , but I can't seem to figure out how to reach the object.
So how could I ask upon pick up hours worked and calculate the info for the unit ?
This sounds like a great moment to use an Interface!
public Interface IRepairable
{
double GetRepairCost();
}
Then redefine Computer
public class Computer : IRepairable
{
public double GetRepairCost()
{
return (this.HoursWorked * 50) + PartsCost;
}
}
and Laptop
public class Laptop : Computer
{
public new double GetRepairCost()
{
return base.GetRepairCost() + 10;
}
}
and Repair
public static class Repair
{
public static Dictionary<string, IRepairable> RepairLog { get; set; }
}
And now you have a dictionary of things that you can call GetRepairCost() on! These could be Computers or Laptops or a mix, it doesn't matter to the RepairLog!

An elegant way to check if any items which has the same childrens exist

I have this item:
public partial class PACK
{
public int PACK_IDE { get; set; }
public string PACK_DESCR { get; set; }
public Nullable<System.DateTime> PACK_DATE_CREATED { get; set; }
public Nullable<System.DateTime> PACK_DATE_MODIFIED { get; set; }
public Nullable<System.DateTime> PACK_DATE_LAST_CALC { get; set; }
public decimal PACK_COST { get; set; }
public int PACK_QTY_POSS { get; set; }
public string PACK_NOTE { get; set; }
public int PACK_QTY_SOLD { get; set; }
public decimal PACK_AVRG_SELL_PRICE { get; set; }
public Nullable<int> PACK_DESTINATION { get; set; }
public virtual ICollection<INVENTORY_PACK> INVENTORY_PACK { get; set; }
}
Which contains, as you can see, a list of Inventory Packs which are shaped like this:
public partial class INVENTORY_PACK
{
public int INVENT_PACK_IDE { get; set; }
public int INVENT_IDE { get; set; }
public int PACK_IDE { get; set; }
public int QTY { get; set; }
public virtual INVENTORY INVENTORY { get; set; }
public virtual PACK PACK { get; set; }
}
And, lastly, the Inventory Items, which has 2 important fields that are of importance right now:
public partial class INVENTORY
{
public int INVENT_IDE { get; set; }
public Nullable<int> CARD_IDE { get; set; }
public Nullable<int> INVENT_NB_IN_STOCK { get; set; }
public Nullable<int> INVENT_NB_QT_SOLD { get; set; }
public string INVENT_ITEM_STATE { get; set; }
public virtual CARD CARD { get; set; }
public virtual ICollection<INVENTORY_PACK> INVENTORY_PACK { get; set; }
}
When I actually save or create a new pack, I need to find a way to check if the actual pack exists that has the exact same Inventory Items based on INVENT_ITEM_STATE and CARD_IDE and, also, of QTY in INVENTORY_PACK. If these three values are identical, then we may consider having the same children. I basically need to search through any Packs (using Linq or any Linq-To-Sql call) which childrens are the same as the one I have right now, but I don't really know how to do this except for massive mind-blowing for/foreach loops.
EDIT
As requested, here's an example of what I've been trying to do.
internal void CreatePack(PackInfo _pack)
{
using (TransactionScope scope = TransactionUtils.CreateTransactionScope())
{
try
{
var packQry = from pa in mDb.PACK
select pa;
if (!packQry.Any())
{
PACK packToAdd = DataConverter.PackInfoToPACKData(_pack);
mDb.PACK.Add(packToAdd);
mDb.SaveChanges();
int packID = mDb.PACK.Max(_x => _x.PACK_IDE);
foreach (INVENTORY_PACK inventoryPack in packToAdd.INVENTORY_PACK)
{
inventoryPack.PACK_IDE = packID;
mDb.SaveChanges();
}
}
else
{
List<PACK> listPacks = new List<PACK>();
foreach (var inventoryPackInfo in _pack.mListInventoryPackInPack)
{
packQry = from pa in mDb.PACK
where pa.INVENTORY_PACK.Any(_item =>
_item.INVENTORY.INVENT_IDE ==
inventoryPackInfo.mInventoryItem.mInventoryID)
where pa.INVENTORY_PACK.Any(
_item =>
_item.INVENTORY.INVENT_ITEM_STATE ==
inventoryPackInfo.mInventoryItem.mItemState)
where pa.INVENTORY_PACK.Any(_item => _item.QTY == inventoryPackInfo.mQuantity)
select pa;
if (packQry.Any())
{
listPacks.AddRange(packQry);
}
}
if (_pack.mListInventoryPackInPack.Count == 1)
{
}
IDictionary<PACK, int> counts = new Dictionary<PACK, int>();
foreach (var pack in listPacks)
{
if (!counts.ContainsKey(pack))
{
counts.Add(pack, 1);
}
else
{
counts[pack]++;
}
}
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
scope.Complete();
}
}
EXAMPLE
I think that I need to clarify my need. Here's an example.
Say that I have 1 PACK containing 2 INVENTORY_PACK: 1 is an INVENTORY item with INVENT_IDE 1234, CARD_IDE 4321, QTY is 1, and INVENT_ITEM_STATE is PERFECT. The second object is INVENT_IDE 4567, CARD_IDE 7654, QTY is 2 and INVENT_ITEM_STATE PERFECT.
I need to check through the packages to see if there's already a package containing exactly there two items in the selected parameters. So there are many possibilities:
If we have another existing PACK that has the same items and the same number of items (in this case, 2), quantities and IDS, we have a perfect match and we consider that the PACK already exists;
If there is a PACK containing the same items, but with another one (3 items or more for this example), is it considered another pack; then we do not have a match;
If any package has only one of these items, we do not have a match.
If I understand well, you could do the following :
Implement two EqualityComparer (may be implemented in your business layer as it's business logic only)
class PACK_Comparer : EqualityComparer<PACK>
{
public override bool Equals(PACK p1, PACK p2)
{
// Two PACK are Equals if their INVENTORYs contains the same INVENTORY items
return (p1.INVENTORY_PACK.Count() == p2.INVENTORY_PACK.Count()
&& p1.INVENTORY_PACK.Intersect(p2.INVENTORY_PACK, new INVENTORY_PACK_Comparer()).Count() == p1.INVENTORY_PACK.Count());
}
public override int GetHashCode(PACK p)
{
// Ensure that if the Equals method returns true for two PACK p1 and p2
// then the value returned by the GetHashCode method for p1 must equal the value returned for p2
INVENTORY_PACK_Comparer comp = new INVENTORY_PACK_Comparer();
int hCode = 0;
foreach (var i in p.INVENTORY_PACK)
hCode ^= comp.GetHashCode(i);
return hCode.GetHashCode();
}
}
class INVENTORY_PACK_Comparer : EqualityComparer<INVENTORY_PACK>
{
public override bool Equals(INVENTORY_PACK i1, INVENTORY_PACK i2)
{
// Two INVENTORY_PACK are Equals if their INVENT_ITEM_STATE, CARD_IDE and QTY are Equals
return (i1.INVENTORY.INVENT_ITEM_STATE == i2.INVENTORY.INVENT_ITEM_STATE
&& i1.INVENTORY.CARD_IDE == i2.INVENTORY.CARD_IDE
&& i1.QTY == i2.QTY);
}
public override int GetHashCode(INVENTORY_PACK i)
{
// Ensure that if the Equals method returns true for two INVENTORY_PACK i1 and i2
// then the value returned by the GetHashCode method for i1 must equal the value returned for i2
int hCode = i.INVENTORY.INVENT_ITEM_STATE.GetHashCode()
^ i.INVENTORY.CARD_IDE.GetHashCode()
^ i.QTY.GetHashCode();
return hCode.GetHashCode();
}
}
Then check if a same PACK already exist is as short as
bool exist = mDb.PACK.Contains(_pack, new PACK_Comparer());
And if you want to fetch the actual PACK which already exist in your mDb :
PACK_Comparer comp = new PACK_Comparer();
PACK existingPack = mDb.PACK.FirstOrDefault(p => comp.Equals(p, _pack));
Note that I removed the 'test is null' things to make it simplier.
You'll need to implement this on your own.
Regards,
Gerard
This is probably what you want
int count = (from p in _pack.INVENTORY_PACK
where pack.INVENTORY.INVENT_ITEM_STATE == p.INVENTORY.INVENT_ITEM_STATE
select p).Count();
After that check for if(pack.QTY == count)

Categories

Resources