ASP.NET MVC Google pie chart controller - c#

I am looking a friends code to implement google charts into my mvc project.
I have a model that I am pulling data from:
public partial class HoursPerSite
{
public string SiteName { get; set; }
public Nullable<decimal> SiteHours { get; set; }
}
The chart has rendered and it looks good but the legend is showing SiteHours and not SiteName as I'd like it to.
Here is the controller part:
// HOLIDAY PIE START
ViewBag.msg = db.HoursPerSites.Count().ToString();
var query = from r in db.HoursPerSites
select new { Count = r.SiteHours, Value = r.SiteHours };
var result2 = query.ToList();
var datachart2 = new object[result2.Count];
int l = 0;
foreach (var i in result2)
{
datachart2[l] = new object[] { i.Value.ToString(), i.Count };
l++;
}
string datastr2 = JsonConvert.SerializeObject(datachart2, Formatting.None);
ViewBag.dataj2 = new HtmlString(datastr2);
// HOLIDAY PIE END
I'd like it so the pie chart legend/key shows the site not the hours.

Not sure but is this:
select new { Count = r.SiteHours, Value = r.SiteHours };
Not supposed to be this: (SiteName):
select new { Count = r.SiteHours, Value = r.SiteName };
Also, your naming is very bad if I may say. That will not make your future work easier. Try naming your variables and obejects more specifically.
EDIT:
You can make use of Regions instead of code comments for example which will make seperation/ordering/viewing of code parts/sections much easier
Naming your variables better will make your life but also other
people working on/with your code easier
I would change your current code to this:
Please note that I don't have any editor and that there could be syntax errors
#region Holiday Pie Chart
ViewBag.msg = db.HoursPerSites.Count().ToString();
var queryHoursPerSites = from r in db.HoursPerSites
select new { Count = r.SiteHours, Value = r.SiteHours };
var resultsQueryHoursPerSites = queryHoursPerSites.ToList(); // or HoursPerSitesCollection
var holidayPieChart = new object[resultsQueryHoursPerSites.Count];
int counter = 0; //
foreach (var record in resultsQueryHoursPerSites)
{
holidayPieChart[counter] = new object[] { record.Value.ToString(), record.Count };
counter++;
}
string deserialisedResults = JsonConvert.SerializeObject(holidayPieChart, Formatting.None);
// no idea what dataj2 is here ...
ViewBag.dataj2 = new HtmlString(deserialisedResults);
#endregion
I am sure there is even more to "improve" or "change" but that would in my opinion already be an improvement.
I am sure others can elaborate even better on what I am suggesting here :)

Related

C# - How to filter list using enum

I have 2 a classes:
public enum ArticleType
{
News = 1;
SpecialOffer = 2;
Service = 3;
}
public ArticleApiDto
{
public int Id;
public ArticleType Type;
}
Now i have method for getting data from db, something like:
public List<ArticleApiDto> GetAll(List<ArticleType> types)
{
var res = new List<ArticleApiDto>();
res = context.articles.ToList();
//do stuff
}
Now I would like to filter out Articles from res whose type is specified in types from parameter of method.
Problem 1: I actually cant use Contains because ArticleType is enum
Problem 2: List<ArticleType> is because sometimes i want to pass only one type but sometimes two or three. At the moment i cant figure out better better solution.
Can someone help me with this please I was searching for whole noone but cant figure out
To be able to pass more than one type you can do it like:
Make your enum to be Flags (note that values now can't be 1,2,3,4 and should be 1,2,4,8,16,...:
[Flags]
public enum ArticleType
{
News = 1;
SpecialOffer = 2;
Service = 4;
}
Now you add up what you want to filter with |:
filter = ArtickeType.News | ArticleType.Service;
var result = res.Where(x => filter & x.Type != 0).ToList();
or:
filter = ArtickeType.News | ArticleType.Service | ArticleType.SpecialOffer;
var result = res.Where(x => filter.HasFlag(x.Type)).ToList();
To do it with your current enum:
public enum ArticleType
{
News = 1;
SpecialOffer = 2;
Service = 3;
}
var filter = new List<ArticleType> { ArticleType.Service, ArticleType.News};
var result = res.Where(x => filter.Contains(x.Type)).ToList();
This code work with me, I use Linq with contains it may solve your problem.
public static List<ArticleApiDto> GetAll(List<ArticleType> types)
{
var res = new List<ArticleApiDto>();
List<ArticleApiDto> articles = new List<ArticleApiDto>
{
new ArticleApiDto{Id = 1, Type = ArticleType.News },
new ArticleApiDto{Id = 2, Type = ArticleType.SpecialOffer },
};
var newArticales = articles.Where(i =>
{
return types.Contains(i.Type);
}).ToList();
return newArticales;
}

How i foreach loop in listitems values entity framework

I have 2 lists. One has 3 records like 1 , 2 , 3 and seconds list holds table records. All i wanna do add first list values to second list.
I hope helps.
foreach (var itemAgent in listofValues)
{
foreach (var item in formSorgu)
{
#region MyRegion
CrmDonusleri crmEkleme = new CrmDonusleri()
{
AradigiBolge = item.bolge,
AramaTarihi = Convert.ToDateTime(item.aratarihi),
Musno = item.musno,
GeriDonusYapildiMi = false,
AtanmaTarihi = DateTime.Now,
KanalAdi = item.kanal,
ProgramAdi = item.program,
AtananAgent = itemAgent
};
DbContext.CrmDonusleri.Add(crmEkleme);
#endregion
}
}
DbContext.SaveChanges();
listofValues hold 3 records and formSorgu hold 2000 records. listofValues as List One and formSorgu as List Two. And i want my final list like Picture below.
I don't think my code is right. Please show me the right way to write this query.
for (int i = formSorgu.Count + 1; i >= 0; i--)
{
foreach (var itemAgent in listofValues)
{
CrmDonusleri crmEkkle = new CrmDonusleri()
{
Musno = formSorgu.FirstOrDefault().musno,
AtananAgent = itemAgent
};
}
}
when i use this code it gets one record from formSorgu but add to listofValues 3 times i just want it to foreach one time and go out from foreach loop and carry on other for loop record.
actually, i love to share i am not like stackover mods. so i found an excellent answer on internet. you can find a link that equally selecting items from list and psuedo run.
solution link
that is a link i used. and i turn my code like this;
var randoAgent = new RandomPicker<string>(listofValues);
foreach (var itemSorgu in formSorgu)
{
var item = randoAgent.PickItem();
CrmDonusleri crmEkle = new CrmDonusleri()
{
Musno = itemSorgu.musno,
TelNo = itemSorgu.telno,
AtananAgent = item,
AradigiBolge = itemSorgu.bolge,
AramaTarihi = Convert.ToDateTime(itemSorgu.aratarihi),
AtanmaTarihi = DateTime.Now,
Ekleyen = itemSorgu.ekleyen,
GeriDonusYapildiMi = false,
KanalAdi = itemSorgu.kanal,
ProgramAdi = itemSorgu.program
};
DbContext.CrmDonusleri.Add(crmEkle);
}
DbContext.SaveChanges();
and works perfect.

Index was out of range. Must be non-negative and less than the size of the collection

I am new in generic collections
I have one class .The class name is ReportSubCategoryModel
these are that class properties
public class ReportSubCategoryModel
{
public string ReporTitle { get; set; }
public string ReporStatus { get; set; }
public string ReportDescription { get; set; }
public int ReporSubCategoryId { get; set; }
public IList<ReportSubCategoryModel> ReportSubCategoryModelList { get; set; }
}
I want to set the lot of values in this class properties from database . So i assigned a list of that class
IList<ReportSubCategoryModel> reportSubCategoryModel = new List<ReportSubCategoryModel>();
Now I want to set a values inside of for loop
IList<ReportSubCategory> reportSubCategory = datamodel.ReportSubCategory.Where(r => r.ReportCategoryId == reportCategoryId).ToList();
for (int i = 0; i < reportSubCategory.Count; i++)
{
int reportSubCategoryId = reportSubCategory[i].ReportSubCategoryId;
ReportStatu reportStatus =
datamodel.ReportStatus.SingleOrDefault(
r => r.ReportSubCategoryId == reportSubCategoryId);
if (reportStatus == null)
{
reportSubCategoryModel[i].ReportDescription = "Dis";**//This line threw the error**
reportSubCategoryModel[i].ReporStatus = "Not Available";
reportSubCategoryModel[i].ReporTitle = reportSubCategory[i].ReportSubCategoryName;
reportSubCategoryModel[i].ReportSubCategoryModelList.Add(reportSubCategoryModel[i]);
}
else
{
reportSubCategoryModel[i].ReportDescription = "Dis";
reportSubCategoryModel[i].ReporStatus = "Available For " + reportStatus.ReportStatusDescription;
reportSubCategoryModel[i].ReporTitle = reportSubCategory[i].ReportSubCategoryName;
reportSubCategoryModel[i].ReporSubCategoryId = reportSubCategoryId;
reportSubCategoryModel[i].ReportSubCategoryModelList.Add(reportSubCategoryModel[i]);
}
}
return reportSubCategoryModel.ToList();
But it's not working.
This line reportSubCategoryModel[i].ReportDescription = "Dis"; give's the error for Index was out of range. Must be non-negative and less than the size of the collection.
You can see this problem and my code from below image.Please zoom your browser (cntrl+Up Mouse Scrolling)
how can i solve this problem ?
I'm not entirely sure what the whole logic is meant to be, but this is how I feel the code should look like:
IList<ReportSubCategory> reportSubCategory = datamodel.ReportSubCategory
.Where(r => r.ReportCategoryId == reportCategoryId)
.ToList();
foreach (var subCategory in reportSubCategory)
{
int reportSubCategoryId = subCategory.ReportSubCategoryId;
ReportStatus reportStatus = datamodel.ReportStatus
.SingleOrDefault(r => r.ReportSubCategoryId == reportSubCategoryId);
if (reportStatus == null)
{
var model = new ReportSubCategoryModel();
model.ReportDescription = "Dis";
model.ReporStatus = "Not Available";
model.ReporTitle = subCategory.ReportSubCategoryName;
// Not sure what this is.
//model.ReportSubCategoryModelList.Add(reportSubCategoryModel[i]);
reportSubCategoryModel.Add(model);
}
else
{
var model = new ReportSubCategoryModel();
model.ReportDescription = "Dis";
model.ReporStatus = "Available For " + reportStatus.ReportStatusDescription;
model.ReporTitle = subCategory.ReportSubCategoryName;
model.ReporSubCategoryId = reportSubCategoryId;
// Not sure what this is either.
//reportSubCategoryModel[i].ReportSubCategoryModelList.Add(reportSubCategoryModel[i]);
reportSubCategoryModel.Add(model);
}
}
return reportSubCategoryModel;
Basically, you new up a model, set the properties and then Add that to the model list; based on iterating the sub category list.
However, I'm not sure what the whole nested list thing is about (the code I commented out).
Also, this code can be further trimmed, but I'll leave that out for now so as not to depart too much from the provided code.
Create a nested loop with in your main loop.With reportSubCategoryModel.Count.
you are treating list as an array.
something similar to following could replace the assigning section
var temp = new ReportSubCategoryModel();
temp.ReportDescription = "dis";
....
reportSubCategoryModel.Add(temp);
should sort the issue.
As far as I can see you have only created the list of reportSubCategoryModel and not yet populated it.
A list does not pre-populate with empty values and will therefore have a length of zero after initialisation. If you with to add new values you need to create your ReportSubCategoryModel object and then add it to the List.
Instead of trying to edit the values of the list;
reportSubCategoryModel[i].ReportDescription = "Dis";
Create the ReportSubCategoryModel object first, fill the data and the use the List.Add method to add it to your List.
ReportSubCategoryModel reportSubCategoryModelObject = new ReportSubCategoryModel();
reportSubCategoryModelObject.ReportDescription = "Dis";**//This line threw the error**
reportSubCategoryModelObject.ReporStatus = "Not Available";
reportSubCategoryModelObject.ReporTitle = reportSubCategory[i].ReportSubCategoryName;
reportSubCategoryModel.Add(reportSubCategoryModelObject);

Creating a two-dimensional array

I am trying to create a two dimensional array and I am getting so confused. I was told by a coworker that I need to create a dictionary within a dictionary for the array list but he couldn't stick around to help me.
I have been able to create the first array that lists the the programs like this
+ project 1
+ project 2
+ project 3
+ project 4
The code that accomplishes this task is below-
var PGList = from x in db.month_mapping
where x.PG_SUB_PROGRAM == SP
select x;
//select x.PG.Distinct().ToArray();
var PGRow = PGList.Select(x => new { x.PG }).Distinct().ToArray();
So that takes care of my vertical array and now I need to add my horizontal array so that I can see the total amount spent in each accounting period. So the final output would look like this but without the dashes of course.
+ program 1-------100---200---300---400---500---600---700---800---900---1000---1100---1200
+ program 2-------100---200---300---400---500---600---700---800---900---1000---1100---1200
+ program 3-------100---200---300---400---500---600---700---800---900---1000---1100---1200
+ program 4-------100---200---300---400---500---600---700---800---900---1000---1100---1200
I have tried to use a foreach to cycle through the accounting periods but it doesn't work. I think I might be on the right track and I was hoping SO could provide some guidance or at the very least a tutorial for me to follow. I have posted the code that I written so far on the second array below. I am using C# and MVC 3. You might notice that their is no dictionary within a dictionary. If my coworker is correct how would I do something like that, I took a look at this question using dictionary as a key in other dictionary but I don't understand how I would use it in this situation.
Dictionary<string, double[]> MonthRow = new Dictionary<string, double[]>();
double[] PGContent = new double[12];
string lastPG = null;
foreach (var item in PGRow)
{
if (lastPG != item.PG)
{
PGContent = new double[12];
}
var MonthList = from x in db.Month_Web
where x.PG == PG
group x by new { x.ACCOUNTING_PERIOD, x.PG, x.Amount } into pggroup
select new { accounting_period = pggroup.Key.ACCOUNTING_PERIOD, amount = pggroup.Sum(x => x.Amount) };
foreach (var P in MonthList)
{
int accounting_period = int.Parse(P.accounting_period) - 1;
PAContent[accounting_period] = (double)P.amount;
MonthRow[item.PG] = PGContent;
lastPG = item.PG;
}
I hope I have clearly explained my issue, please feel free to ask for any clarification needed as I need to solve this problem and will be checking back often. Thanks for your help!
hope this helps.
// sample data
var data = new Dictionary<string, List<int>>();
data.Add("program-1", new List<int>() { 100, 110, 130 });
data.Add("program-2", new List<int>() { 200, 210, 230 });
data.Add("brogram-3", new List<int>() { 300, 310, 330 });
// query data
var newData = (from x in data
where x.Key.Contains("pro")
select x).ToDictionary(v => v.Key, v=>v.Value);
// display selected data
foreach (var kv in newData)
{
Console.Write(kv.Key);
foreach (var val in kv.Value)
{
Console.Write(" ");
Console.Write(val.ToString());
}
Console.WriteLine();
}
output is:
program-1 100 110 130
program-2 200 210 230
Don't try to use anonymous types or LINQ projection to create new data types, especially if you're a beginner, you will just get confused. If you want a specialized data type, define one; e.g.:
public class Account
{
public string Name { get; private set; }
public decimal[] MonthAmount { get; private set; }
readonly int maxMonths = 12;
public Account(string name, ICollection<decimal> monthAmounts)
{
if (name == null)
throw new ArgumentNullException("name");
if (monthAmounts == null)
throw new ArgumentNullException("monthAmounts");
if (monthAmounts.Count > maxMonths)
throw new ArgumentOutOfRangeException(string.Format(" monthAmounts must be <= {0}", maxMonths));
this.Name = name;
this.MonthAmount = new decimal[maxMonths];
int i = 0;
foreach (decimal d in monthAmounts)
{
this.MonthAmount[i] = d;
i++;
}
}
}
Use instances of this type directly, you do not have to convert them to arrays, dictionaries, lists, or anything else:
var accountPeriods = new List<Account>();
accountPeriods.Add(new Account("program-1", new decimal[] { 1, 2, 3, 4 }));
You can use LINQ or whatever to query or alter instances of your new type:
foreach (Account a in accountPeriods)
foreach (decimal d in a.MonthAmount)
DoSomethingWith(d);
That should be enough to get you started.
I want to thank #Ray Cheng and #Dour High Arch for their help but I have figured out another way to accomplish this task and I wanted to post my code so that the next person that is having the same trouble can figure out their problem faster.
Above I split my code into more managable sections to explain my problem as clearly as I could and the code below has all those parts combined so you can see the big picture. This code returns an array that contains the program and the amounts for every month.
public virtual ActionResult getAjaxPGs(string SP = null)
{
if (SP != null)
{
var PGList = from x in db.month_mapping
where x.PG_SUB_PROGRAM == SP
select x;
var PGRow = PGList.Select(x => new { x.PG }).Distinct().ToArray();
float[] PGContent = new float[12];
Dictionary<string,float[]> MonthRow = new Dictionary<string, float[]>();
foreach (var item in PGRow)
{
PGContent = new float[12];
var MonthList = from x in db.month_Web
where x.PG == item.PG
group x by new { x.ACCOUNTING_PERIOD, x.PG, x.Amount } into pggroup
select new { accounting_period = pggroup.Key.ACCOUNTING_PERIOD, amount = pggroup.Sum(x => x.Amount) };
foreach (var mon in MonthList)
{
int accounting_period = int.Parse(mon.accounting_period) - 1;
PGContent[accounting_period] = (float)mon.amount/1000000;
}
MonthRow[item.PG] = PGContent;
}
return Json(MonthRow, JsonRequestBehavior.AllowGet);
}
return View();
}
This code worked great for me since I am pulling from a Linq to SQL query instead of adding data directly into the code. My problems stemmed from mainly putting the data pulls outside of the foreach loops so it only pulled 1 piece of data from the SQL instead of all twelve months. I hope this helps some one else who is trying to pull data in from SQL data sources into multidimensional arrays.

create an array of anonymous type

I am trying to get data from database for Google charts in my program. I would like to create an array of anonymous type (var) instead of repeating my code over and over again:
public JsonResult GetChartData(int sID, int regionID)
{
var testPathOne = from p in _rep.GetMetricsData().GetLHDb().page_loads
where p.t_3id == sID && p.test_path_id == 1
select new { time = p.time, created_at = p.created_at };
var testPathTwo = from p in _rep.GetMetricsData().GetLHDb().page_loads
where p.t_3id == sID && p.test_path_id == 2
select new { time = p.time, created_at = p.created_at };
var tOne = testPathOne.ToArray();
var tTwo = testPathTwo.ToArray();
var name = new { test1 = tOne, test2 = tTwo };
return Json(name);
}
i know that i will need a for loop so i can go through all the test path id's instead of hard coding them like this p.test_path_id == 1, but my question is how would i make this part dynamic var name = new { test1 = tOne, test2 = tTwo };
Edit:
I apologize, I would like to do something like this:
name is an array
for loop:
testPath = query
name.Add(testPath)
I hope that makes sense
The easiest solution in this particular case would be to just give a name to the class that is currently anonymous. While there are workarounds that you can use, when you need to start working really hard to use an anonymous type you probably shouldn't be using it. It's there to make certain tasks quicker and easier; if that isn't happening then you are likely better off with a real class.
That solution would look something like this:
//Please give me a real name
public class ClassToBeRenamed
{
public DateTime Time { get; set; }
public DateTime CreatedAt { get; set; }
}
List<ClassToBeRenamed[]> myList = new List<ClassToBeRenamed[]>();
for (int i = 0; i < 10; i++)
{
myList.Add((from p in _rep.GetMetricsData().GetLHDb().page_loads
where p.t_3id == sID && p.test_path_id == i
select new ClassToBeRenamed { Time = p.time, CreatedAt = p.created_at })
.ToArray());
}
Having said all of that, it's still possible.
var myList = new[]{
from p in _rep.GetMetricsData().GetLHDb().page_loads
where p.t_3id == sID && p.test_path_id == 1
select new { time = p.time, created_at = p.created_at }.ToArray()
}.ToList();
for (int i = 2; i < 10; i++)
{
myList.Add(from p in _rep.GetMetricsData().GetLHDb().page_loads
where p.t_3id == sID && p.test_path_id == i
select new { time = p.time, created_at = p.created_at }.ToArray()
);
}
var myArray = myList.ToArray();
If it's really, really important that you have an array, and not a list, then you could call ToArray on myList at the very end. It's important that you start out with a list, and only convert it to an array at the end because Arrays have a fixed size once they are created. You can mutate their contents, but you can't make them bigger or smaller. A List on the other hand, is designed to mutate it's size over time, so it can start out with 0 or 1 items and then add items over time, which is important for us in this particular context. (It's actually useful quite often, which is why it is frequently useful to use List over arrays.)
Instead of using LINQ use foreach loops. You are more limited with LINQ.
Also define your ArrayLists at the beginning and add to them as you go.
var test1 = new ArrayList();
var test2 = new ArrayList();
foreach(PageLoad p in _rep.GetMetricsData().GetLHDb().page_loads)
{
if(p.t_3id == sID)
{
var tr = new { time = p.time, created_at = p.created_at };
switch(p.test_path_id)
{
case 1: test1.Add(tr); break;
case 2: test2.Add(tr); break;
}
}
}
return Json(new { test1, test2, });
You do not need to define the names of properties anonymous types because they default to the variable names.

Categories