Having some issues with my code, its a many to many between 3 tables, im using LINQ to entities, first I group the quote ids then use the id to get the info from each table and try to put it into a viewmodel, im not sure my inhertance is right
There should be one quote with multiple prices from multiple suppliers for multiple items, the item names need to be in the column and the prices below.
Anyway the issue below is
Error 3 The best overloaded method match for
System.Collections.Generic.List<ITAPP.Models.tblQuotes>.Add(ITAPP.Models.tblQuotes)
has some invalid arguments PurchasingController.cs 48 17 ITAPP`
Error 4 Argument 1: cannot convert from
System.Collections.Generic.List<ITAPP.Models.tblQuotes>' to 'ITAPP.Models.tblQuotes'
PurchasingController.cs 48 37 ITAPP`
and here is the code
var tblQuoting =
from d in db.Quotes_Items_Suppliers
group d by new
{
d.QuoteID
} into g
select new {
QuoteID = g.Key
};
var model = new List<QuoteViewModel>();
foreach (var Quotes in tblQuoting)
{
var ModelItem = new QuoteViewModel();
ModelItem.Quote = new List<tblQuotes>();
ModelItem.Suppliers = new List<tblSuppliers>();
ModelItem.Items = new List<tblItems>();
ModelItem.Prices = new List<tblQuotes_Items_Suppliers>();
//Add the quote info to model
int QuoteID = Convert.ToInt32(Quotes.QuoteID);
var Quote = (from d in db.Quotes
where d.ID == QuoteID
select d).ToList();
ModelItem.Quote.Add(Quote);
//add all the suppliers to the quote model
var Suppliers = (from d in db.Quotes_Items_Suppliers.Include(t => t.tblSuppliers)
where d.QuoteID == QuoteID
select d).ToList();
ModelItem.Suppliers.Add(Suppliers);
//add the items to the quote model
var Items = (from d in db.Quotes_Items_Suppliers.Include(t => t.tblItems)
where d.QuoteID == QuoteID
select d).ToList();
ModelItem.Items.Add(Items);
model.Add(ModelItem);
}
return View("Index", model);
this is my model (if its right?)
public class QuoteViewModel
{
public List<tblQuotes> Quote { get; set; }
public List<tblSuppliers> Suppliers { get; set; }
public List<tblItems> Items { get; set; }
public List<tblQuotes_Items_Suppliers> Prices { get; set; }
}
index
Use AddRange to add sequence of items to list:
ModelItem.Quote.AddRange(Quote);
ModelItem.Suppliers.AddRange(Suppliers);
ModelItem.Items.AddRange(Items);
Or simply assign lists without initialization (thus you will avoid creating intermediate list and copying items from one list to another):
ModelItem.Quote = Quote;
ModelItem.Suppliers = Supplies;
ModelItem.Items = Items;
Or even use object initalizer:
var ModelItem = new QuoteViewModel {
Quote = db.Quotes.Where(q => q.ID == QuoteID).ToList(),
Suppliers = db.Quotes_Items_Suppliers.Include(t => t.tblSuppliers)
.Where(s => s.QuoteID == QuoteID).ToList(),
Items = db.Quotes_Items_Suppliers.Include(t => t.tblItems)
.Where(i => i.QuoteID == QuoteID).ToList()
};
Related
My first post. Humbled by this community. Thank you.
The goal: Create a new List<PropertyB> based on two other lists:
List<PropertyA> and another List<PropertyB>.
For each PropertyA in the List<PropertyA>, create a new PropertyB(), assigning the DisplayName to the new PropertyB's Name property. For each property in 'List', if the name from PropertyA matches PropertyB, assign the value to the new list's value property.
The problem: Accounting for Duplicate values. No data loss can occur between the lists.
The new list should include: Every PropertyA and every Value of the PropertyB list where there is a Name match.
The types:
My thoughts: My gut says the inner loop should check whether something has already been added to the collection. Or perhaps an accounting of duplicate values (ie: the index of duplicates?)
Any assistance is appreciated!
public class PropertyA{
private string DisplayName{get; set;}
private string Name {get; set;}
private string Value {get; set;}
}
public class PropertyB{
private string Name{get; set;}
private string Value{get; set;}
}
Initialization:
List<PropertyA> listA = new List<PropertyA>()
{
new PropertyA(){ DisplayName="LOB", Name="lineofbusiness", Value="test"},
new PropertyA(){ DisplayName="ABC", Name="alpha", Value="test2"},
new PropertyA(){ DisplayName="DEF", Name="beta", Value="test3"},
new PropertyA(){ DisplayName="GHI", Name="zeta", Value="test4"},
new PropertyA(){ DisplayName"Line of Business", Name="lineofbusiness", Value="test5"
};
List<PropertyB> listB = new List<PropertyB>()
{
new PropertyB(){ Name="lineofbusiness", Value="test789"},
new PropertyB(){ Name="alpha", Value="test234"},
new PropertyB(){ Name="lineofbusiness", Value="test456"},
new PropertyB(){ Name="beta", Value="test123"},
};
In Main:
List<PropertyB> newList = new List<PropertyB>();
foreach(PropertyA propA in listA){
PropertyB newProp = new PropertyB();
newProp.Name = propA.DisplayName;
foreach(PropertyB propB in listB){
if(propA.Name == propB.Name){
newProp.Value = propB.Value;
break;
}
}
newList.Add(newProp);
}
UPDATE:
The console output (if you choose) should be as follows:
LOB test789
ABC test234
DEF test123
GHI null
Line of Business test456
if you simply remove the break; you end up with:
LOB test456
ABC test234
DEF test123
GHI null
Line of Business test456
The inner loop will always assign the LAST name match value. That's a problem.
you can just fix your code, add a check for duplicates
List<PropertyB> newList = new List<PropertyB>();
foreach(PropertyA propA in listA)
{
PropertyB newProp = new PropertyB();
newProp.Name = propA.DisplayName;
foreach (var propB in listB)
{
if (propA.Name == propB.Name)
{
if( newList.Any(l =>l.Value==propB.Value )) continue;
newProp.Value = propB.Value;
break;
}
}
newList.Add(newProp);
}
but to make it more reliable I would offer this
List<PropertyA> newList = new List<PropertyA>();
foreach (var propA in listA)
{
var newProp = new PropertyA();
newProp.Name = propA.DisplayName;
newProp.DisplayName = propA.Name;
foreach (var propB in listB)
{
if (propA.Name == propB.Name)
{
if (newList.Any(l => l.Value == propB.Value
&& l.DisplayName==propA.Name)) continue;
newProp.Value = propB.Value;
break;
}
}
newList.Add(newProp);
}
var result = newList.Select(l => new PropertyB {Name=l.Name, Value=l.Value} );
both algorithms show the same result during the test
LOB test789
ABC test234
DEF test123
GHI null
Line of Business test456
I understood the process:
list of A needs turning into a list of B
Some of the list of B items might have a Value copied from some other list of B
var d = bList.ToDictionary(b => b.Name, b => b.Value);
var newB = aList.Select(a => new B { Name = a.DisplayName, Value = d.GetValueOrDefault(a.Name) } ).ToList();
You said no data shall be lost but I think inherently you must have to throw something away because B has fewer properties than A and some properties from B are used to "overwrite"/take the place of those in A..
I note also you have duplicated Name in your sample data list B, which the ToDictionary won't tolerate. You didn't specify how to resolve this but you'll have to choose (if it truly does occur) what value to pick or if to take multiple. This, for example, would tolerate duplicate names
var d = bList.ToLookup(b => b.Name, b => b.Value);
var newB = aList.Select(a => new B { Name = a.DisplayName, Value = d[a.Name]?.First() } ).ToList();
Again, this throws stuff away.. if you want to keep all the values you'll have to encode the Value somehow
Value = string.Join(",", d[a.Name])
for example
So, it looks like you want to keep all the duplicates and dispense them in order. We could do that by grouping these things into a list that we pull the items out of as we enumerate
var d = bList.GroupBy(b => b.Name, b => b.Value).ToDictionary(g => g.Key, g => g.ToList());
var newB = new List<B>();
foreach(var a in aList){
var b = new B { Name = a.DisplayName };
if(d.TryGetValue(a.Name, out var lst)){
b.Value = lst[0];
lst.RemoveAt(0);
}
}
Im trying to create a table that counts all orders and groups them in a table from sql to linq to use in a bar graph with google charts.
Table`
Orders Status
8 Created
3 Delayed
4 Enroute
sql
SELECT Count (OrderID) as 'Orders', order_status FROM [ORDER]
where order_status ='Created'OR order_status= 'Delayed' OR order_status='Enroute'
group by order_status
controller
public ActionResult GetChart()
{
var Orders = db.Order.Select(a => new { a.OrderID, a.order_status })
.GroupBy(a => a.order_status);
return Json(Orders, JsonRequestBehavior.AllowGet);
}
this is not displaying the correct results as the linq seems to be wrong.
can someone please point me in the right direction? I am relatively new to this.
thanks in advance.
This should work:-
var result = db.Order.Where(x => x.order_status == "Created"
|| x.order_status == "Delayed"
|| x.order_status == "Enroute")
.GroupBy(x => x.order_status)
.Select(x => new
{
order_status = x.Key,
Orders = x.Count()
});
Or if you prefer query syntax then:-
var result = from o in db.Order
where o.order_status == "Created" || o.order_status == "Delayed"
|| o.order_status == "Enroute"
group o by o.order_status
select new
{
orderStatus = x.Key,
Counts = x.Count()
};
I think you want to group by Status and count total number of orders in each group (I build a simple console program to demonstrate). I suppose the data is:
Orders Status
8 Created
3 Delayed
4 Enroute
2 Created
1 Delayed
Order.cs
public class Order
{
public Order(int orderId, string status)
{
OrderId = orderId;
Status = status;
}
public int OrderId { get; set; }
public string Status { get; set; }
}
Program.cs
class Program
{
static void Main(string[] args)
{
// Data
var orders = new List<Order>
{
new Order(8, "Created"),
new Order(3, "Delayed"),
new Order(4, "Enroute"),
new Order(2, "Created"),
new Order(1, "Delayed"),
};
// Query
var query = orders
.GroupBy(x => x.Status)
.Select(x => new {Status = x.Key, Total = x.Count()});
// Display
foreach (var item in query)
{
Console.WriteLine(item.Status + ": " + item.Total);
}
Console.ReadLine();
}
}
The one you need to focus in is query. After using GroupBy, you will have a list of groups. For each group, the Key is the criteria to group (here is the Status). Then, we call Count() to get the total number of element in that group.
So, from the program above, the output should be:
Created: 2
Delayed: 2
Enroute: 1
The following data is returned from an SQL View:
Name CandidateID Filled
Tom Jones 1003436 2014-05-09 07:13:53.087
Tom Jones 1003436 2014-05-09 07:13:18.957
Ed Harris 1421522 2014-05-09 08:17:20.234
I only want the one Tom Jones record with the latest Filled time. How can I achive this in C#/LINQ while getting or after getting data from server?
Maybe something like this:
var q = from n in table
group n by new {n.CandidateID,n.Name} into g
select new
{
CandidateID = g.Key.CandidateID,
Name = g.Key.Name,
Filled = g.Max(t=>t.Filled)
};
Test class
class Foo
{
public string Name { get; set; }
public int CandidateID { get; set; }
public DateTime Filled { get; set; }
}
Test case
var ls=new List<Foo>
{
new Foo(){Name="Tom Jones",CandidateID=1003436,
Filled=DateTime.Parse("2014-05-09 07:13:53.087")},
new Foo(){Name="Tom Jones",CandidateID=1003436,
Filled=DateTime.Parse("2014-05-09 07:13:18.957")},
new Foo(){Name="Ed Harris",CandidateID=1421522,
Filled=DateTime.Parse("2014-05-09 08:17:20.234")}
};
var q =
(from n in ls
group n by new {n.CandidateID,n.Name} into g
select new
{
CandidateID = g.Key.CandidateID,
Name = g.Key.Name,
Filled = g.Max(t=>t.Filled)
});
Output
CandidateID Name Filled
1003436 Tom Jones 09/05/2014 7:13:53 AM
1421522 Ed Harris 09/05/2014 8:17:20 AM
var q = from n in table
group n by n.CandidateID into g
select g.OrderByDescending(t=>t.Filled).FirstOrDefault();
you need Group by as shown below
var distinctItems = ls.GroupBy(x => x.CandidateID).Select(y => y.First());
In this example class IcdPatient represents a many-to-many relationship between a Patient table (not shown in this example) and a lookup table Icd.
public class IcdPatient
{
public int PatientId { get; set; }
public int ConditionCode { get; set; }
public static List<IcdPatient> GetIcdPatientList()
{
return new List<IcdPatient>()
{
new IcdPatient { PatientId = 100, ConditionCode = 111 },
new IcdPatient { PatientId = 100, ConditionCode = 222 },
new IcdPatient { PatientId = 200, ConditionCode = 111 },
new IcdPatient { PatientId = 200, ConditionCode = 222 },
new IcdPatient { PatientId = 3, ConditionCode = 222 },
};
}
}
public class Icd
{
public int ConditionCode { get; set; }
public string ConditionName { get; set; }
public static List<Icd> GetIcdList()
{
return new List<Icd>()
{
new Icd() { ConditionCode =111, ConditionName ="Condition 1"},
new Icd() { ConditionCode =222, ConditionName ="Condition 2"},
};
}
}
I would like for the user to be able to enter as many conditions as they want, and get a LINQ object back that tells them how many PatientIds satisfy that query. I've come up with:
List<string> stringFilteredList = new List<string> { "Condition 1", "Condition 2" };
List<int> filteringList = new List<int> { 111,222 };
var manyToMany = IcdPatient.GetIcdPatientList();
var icdList = Icd.GetIcdList();
/*Working method without joining on the lookup table*/
var grouped = from m in manyToMany
group m by m.PatientId into g
where g.Count() == filteringList.Distinct().Count()
select new
{
PatientId = g.Key,
Count = g.Count()
};
/*End*/
foreach (var item in grouped)
{
Console.WriteLine(item.PatientId);
}
Let's say that IcdPatient has a composite primary key on both fields, so we know that each row is unique. If we find the distinct number of entries in filteringList and do a count on the number of times a PatientId shows up, that means we've found all the people who have all conditions. Because the codes can be esoteric, I would like to do something like
let the user table in the ConditionName in type Icd and perform the same operation. I've not used LINQ this way a lot and I've gathered:
List<int> filteringList = new List<int> { 111,222 };
List<string> stringFilteredList= new List<string>{"Condition 1","Condition 2" };
filteringList.Distinct();
var manyToMany = IcdPatient.GetIcdPatientList();
var icdList = Icd.GetIcdList();
/*Working method without joining on the lookup table*/
var grouped = from m in manyToMany
join i in icdList on
m.ConditionCode equals i.ConditionCode
//group m by m.PatientId into g
group new {m,i} by new { m.ConditionCode }into g
where g.Count() == filteringList.Distinct().Count()
select new
{
Condition = g.Key.ConditionCode
};
/*End*/
but can't get anything to work. This is essentially a join on top of my first query, but I'm not getting what I need to group on.
You don't need to group anything in this case, just use a join and a contains:
List<string> stringFilteredList= new List<string>{"Condition 1","Condition 2" };
var patients =
from icd in Icd.GetIcdList()
join patient in IcdPatient.GetIcdPatientList() on icd.ConditionCode equals patient.ConditionCode
where stringFilteredList.Contains(icd.ConditionName)
select patient.PatientId;
Let's say that IcdPatient has a composite primary key on both fields, so we know that each row is unique. If we find the distinct number of entries in filteringList and do a count on the number of times a PatientId shows up, that means we've found all the people who have all conditions. Because the codes can be esoteric, I would like to do something like let the user table in the ConditionName in type Icd and perform the same operation.
I believe you're asking:
Given a list of ConditionCodes, return a list of PatientIds where every patient has every condition in the list.
In that case, the easiest thing to do is group your IcdPatients table by Id, so that we can tell every condition that a patient has by looking once. Then we check that every ConditionCode we're looking for is in the group. In code, that looks like:
var result = IcdPatient.GetIcdPatientList()
// group up all the objects with the same PatientId
.GroupBy(patient => patient.PatientId)
// gather the information we care about into a single object of type {int, List<int>}
.Select(patients => new {Id = patients.Key,
Conditions = patients.Select(p => p.ConditionCode)})
// get rid of the patients without every condition
.Where(conditionsByPatient =>
conditionsByPatient.Conditions.All(condition => filteringList.Contains(condition)))
.Select(conditionsByPatient => conditionsByPatient.Id);
In query format, that looks like:
var groupedInfo = from patient in IcdPatient.GetIcdPatientList()
group patient by patient.PatientId
into patients
select new { Id = patients.Key,
Conditions = patients.Select(patient => patient.ConditionCode) };
var resultAlt = from g in groupedInfo
where g.Conditions.All(condition => filteringList.Contains(condition))
select g.Id;
Edit: If you'd also like to let your user specify the ConditionName rather than the ConditionId then simply convert from one to the other, storing the result in filteringList, like so:
var conditionNames = // some list of names from the user
var filteringList = Icd.GetIcdList().Where(icd => conditionNames.Contains(icd.ConditionName))
.Select(icd => icd.ConditionCode);
I created a Web Api in VS 2012.
I am trying to get all the value from one column "Category", that is all the unique value, I don't want the list to be returned with duplicates.
I used this code to get products in a particular category. How do I get a full list of categories (All the unique values in the Category Column)?
public IEnumerable<Product> GetProductsByCategory(string category)
{
return repository.GetAllProducts().Where(
p => string.Equals(p.Category, category, StringComparison.OrdinalIgnoreCase));
}
To have unique Categories:
var uniqueCategories = repository.GetAllProducts()
.Select(p => p.Category)
.Distinct();
var uniq = allvalues.GroupBy(x => x.Id).Select(y=>y.First()).Distinct();
Easy and simple
I have to find distinct rows with the following details
class : Scountry
columns: countryID, countryName,isactive
There is no primary key in this. I have succeeded with the followin queries
public DbSet<SCountry> country { get; set; }
public List<SCountry> DoDistinct()
{
var query = (from m in country group m by new { m.CountryID, m.CountryName, m.isactive } into mygroup select mygroup.FirstOrDefault()).Distinct();
var Countries = query.ToList().Select(m => new SCountry { CountryID = m.CountryID, CountryName = m.CountryName, isactive = m.isactive }).ToList();
return Countries;
}
Interestingly enough I tried both of these in LinqPad and the variant using group from Dmitry Gribkov by appears to be quicker. (also the final distinct is not required as the result is already distinct.
My (somewhat simple) code was:
public class Pair
{
public int id {get;set;}
public string Arb {get;set;}
}
void Main()
{
var theList = new List<Pair>();
var randomiser = new Random();
for (int count = 1; count < 10000; count++)
{
theList.Add(new Pair
{
id = randomiser.Next(1, 50),
Arb = "not used"
});
}
var timer = new Stopwatch();
timer.Start();
var distinct = theList.GroupBy(c => c.id).Select(p => p.First().id);
timer.Stop();
Debug.WriteLine(timer.Elapsed);
timer.Start();
var otherDistinct = theList.Select(p => p.id).Distinct();
timer.Stop();
Debug.WriteLine(timer.Elapsed);
}