Assign List property on Select LINQ statement - c#

So i want to achieve something like:
var query = from p in db.Project
select new A
{
Project = p,
Capacity = new List<Capacity>((from pp in db.ProjectActualCapacity
where pp.ProjectID == p.ID
select new Capacity
{
Actual = pp.Hours,
Date = pp.Date,
ProjectID = pp.ProjectID
}
).ToList())
};
However, when the query is converted to list. It throws the following error
Only parameterless constructors and initializers are supported in LINQ to Entities.
Is there a workaround to this?
thanks
//Update
public class Capacity
{
public DateTime Date { get; set; }
public decimal? Actual { get; set; }
public decimal? Projected { get; set; }
public int ProjectID { get; set; }
public decimal Rate { get; set; }
}

You are explicitly creating a list and using the constructor which accepts an enumerable. This is not necessary since you are already using .ToList() where you define that collection.
Also, your Capacity class needs a parameterless constructor.
So I think it will work like this.
var query = from p in db.Project
select new A {
Project = p,
Capacity = (from pp in db.ProjectActualCapacity
where pp.ProjectID == p.ID
select new Capacity {
Actual = pp.Hours,
Date = pp.Date,
ProjectID = pp.ProjectID
}
).ToList())
};

Related

Comparing two table IDs. ASP.NET MVC

I am currently loading two Orders and Colors tables, I wanted the Colors table to list the items that have the ID equal to Orders. For this, what occurred to me was to assign the IdOrders values ​​to a variable and compare it with my IdOrders (in my table Colors), but it is not possible to assign the database's balance to my variable
My tables:
public partial class Orders
{
public int ID_Orders { get; set; }
public Nullable<System.DateTime> Data_Registo { get; set; }
public string Num_Encomenda { get; set; }
public string Ref_Cliente { get; set; }
}
public partial class Colors
{
public int ID_Orders { get; set; }
public int ID_Programa_Malha { get; set; }
public int ID_Linha_Cor { get; set; }
public string Cor { get; set; }
}
I am working with a database already in operation and possible these tables are already used in a sql join but not how to process that information.
As I said the first thing I remembered was to do this:
My Controller:
var id = from d in db.Orders
select d.ID_Orders;
var color = db.Colors.Where(x => x.ID_Orders = id).ToList();
var tables = new EncomendaViewModel
{
Orders= db.Orders.ToList(),
Colors= color.ToList(),
};
return View(tables);
Error in id: CS0029 C# Cannot implicitly convert type to 'int'
Is it possible to process the data in this way?
Thanks for anyone who can help!
-------------------(Update)------------------------------------------------
Using == cs0019 operator '==' cannot be applied to operands of type
My view in Broswer
dbEntities sd = new dbEntities();
List<Orders> orders= sd.Orders.ToList();
List<Colors> colers= sd.Colors.ToList();
var multipletable = from c in orders
join st in colers on c.ID_Programa equals st.ID_Programa into table1
from st in table1.DefaultIfEmpty()
select new MultipleClass { orders= c, colers= st };
There could be one or more values returned from the below query.
var id = from d in db.Orders
select d.ID_Orders;
That is the reason why it was throwing an error.
So lets try it this way
var color = db.Colors.Where(x => id.Contains(x.ID_Orders)).ToList();
public class OrderWithColorsViewModel
{
public Order order { get; set; }
public List<Colors> colers{ get; set; }
}
Public class TestOrderController : Controller
{
public DailyMVCDemoContext db = new DailyMVCDemoContext();
public ActionResult Index()
{
var orders= db.Orders.ToList();
var colers = db.Colors.ToList();
var result = (from c in orders
join st in colers on c.ID_Orders equals st.id into table1
select new OrderWithColorsViewModel { order =c, colers =
table1.ToList() }).ToList();
return View(result);
}
}
credits: YihuiSun

C# cannot convert class to IEnumerable

I am trying to convert my class to a IEnumerable object.
My class is:
public class StageTwo : IEnumerable
{
public string Party { get; set; }
public string Currency { get; set; }
public string DrCr { get; set; }
public string Account { get; set; }
public double? Amount { get; set; }
public IEnumerator GetEnumerator()
{
return GetEnumerator();
}
}
Below I have a method where I query some data and place it successfully into my StageTwo object. Then I want to duplicate most of the data and changes -item.Amount.
public IEnumerable<StageTwo> Stage2Entries()
{
var queryJoin = (from inn in db.Input.Take(1)
join y in db.InputY on inn.YAction equals y.YAction
orderby inn.Id descending
select new StageTwo
{
Id = inn.Id,
Party = inn.XParty,
Currency = inn.Curr,
DrCr = y.DrAccount1,
Account = y.YAction,
Amount = inn.Amount
});
/*WORKS FINE ABOVE*/
StageTwo stageTwoFinal = new StageTwo();
foreach (var item in queryJoin)
{
stageTwoFinal.Id = item.Id;
stageTwoFinal.Party = item.Party;
stageTwoFinal.Currency = item.Currency;
stageTwoFinal.DrCr = item.DrCr;
stageTwoFinal.Account = item.Account;
stageTwoFinal.Amount = item.Amount;
stageTwoFinal.Id = item.Id;
stageTwoFinal.Party = item.Party;
stageTwoFinal.Currency = item.Currency;
stageTwoFinal.DrCr = item.DrCr;
stageTwoFinal.Account = item.Account;
stageTwoFinal.Amount = -item.Amount;
}
/*Unable to convert here*/
var collection = (IEnumerable<StageTwo>)stageTwoFinal;
return stageTwoFinal;
}
I am getting a System.InvalidCastException
How can I convert this class to an IEnumerable?
If you want to return the query results just write :
return queryJoin.ToList()
That executes the query and returns the results as a list. You need nothing more than :
public IEnumerable<StageTwo> Stage2Entries()
{
var queryJoin = (from inn in db.Input.Take(1)
join y in db.InputY on inn.YAction equals y.YAction
orderby inn.Id descending
select new StageTwo
{
Id = inn.Id,
Party = inn.XParty,
Currency = inn.Curr,
DrCr = y.DrAccount1,
Account = y.YAction,
Amount = inn.Amount
});
return queryJoin.ToList();
}
IEnumerable<T> is the interface implemented by all collections. StageTwo represents a a single object though so it doesn't make any sense for it to implement IEnumerable<T>
If you use EF/EF Core, you can execute the query asynchronously (ie without blocking) with ToListAsync() :
public async Task<IEnumerable<StageTwo>> Stage2Entries()
{
...
var list=await queryJoin.ToListAsync();
return list;
}
You don´t need to implement IEnumerable or its generic version IEnumerable<T> in order to put elements of your class into a collection. Having said this you probably don´t want to implement the interface:
public class StageTwo
{
public string Party { get; set; }
public string Currency { get; set; }
public string DrCr { get; set; }
public string Account { get; set; }
public double? Amount { get; set; }
}
In other words your StageTwo-instances aren´t collections themeselves. Instead they are just elements within a collection.
Now you can create instances of that class within your query and return that query:
var queryJoin = (from inn in db.Input.Take(1)
join y in db.InputY on inn.YAction equals y.YAction
orderby inn.Id descending
select new StageTwo
{
Id = inn.Id,
Party = inn.XParty,
Currency = inn.Curr,
DrCr = y.DrAccount1,
Account = y.YAction,
Amount = inn.Amount
});
return queryJoin;
You see you don´t need all that looping and casting at all, because queryJoin already is an IEnumerable<StageTwo>.
Be aware that the query is executed deferredly, which means it runs when you iterate the elements (e.g. by using a foreach or ToList). So you don´t see the results of that query imediately, you have to explicitely execute that query. See Deferred execution in C# for an explanation on this.

Write own functions to be used in c# linq statement

I have an object
public class Product{
public int Id { get; set; }
public double Cost { get; set; }
public DateTime DatePurchased { get; set; }
public string Name { get; set; }
public string Barcode { get; set; }
public string Category { get; set; }
}
I also have a function public void TotalProductDiscountHistory(DateTime datePurchased, double cost) that does some complex maths and return the discount values from the day it was purchased to date.
I would like to basically be able to call this function inside my query statement to return the sum of all possible for all products as show below.
var query = db.Products.where(x => x.clientId == clientId)
.GroupBy(c => c.Category).Select(a => new {
Category = a.Category,
Cost = a.Sum(u => u.Cost),
TotalDiscounts = a.Sum( TotalProductDiscountHistory(a.DatePurchased,
a.Cost))
});
My questions is how do I achieve this or rather how do I create a function so that I am able to call it within a linq query statement, pass values and return a result.
Your main problem is that the EF is trying to convert the LINQ query into SQL. As there is no SQL equivalent of your function, it really has to just pluck out the data needed for that calculation, and do it after the SQL query, in code.
Linq2SQL was excellent as handling that automatically. EF (even after 6 versions), not so much.
So, we'll have to do it manually:
public double TotalProductDiscountHistory(DateTime datePurchased, double cost) {...}
class CategoryTotals
{
public int Category {get; set;}
public double Cost {get; set;}
public double TotalDiscounts {get; set;}
}
var query = from p in db.Products
where P.clientId == clientId
group p by p.Category;
var totals = new List<CategoryTotals>();
foreach(var grp in query)
{
var ct = new CategoryTotals
{
Category =grp.Category,
Cost = grp.Sum(u => u.Cost),
TotalDiscounts = grp.Sum(u=>
TotalProductDiscountHistory(u.DatePurchased, u.Cost))
};
totals.add(ct);
}

Linq fill data for nested List<T>

I have this Model
public class CPMC
{
public int CPMCId { get; set; }
public List<TPM> tpm = new List<TPM>();
public List<TPMC> tpmc = new List<TPMC>();
}
public class TPMC
{
public int Id { get; set; }
public Int64 Amount { get; set; }
public int PId { get; set; }
public Int64 PAmount { get; set; }
public int CPMCId { get; set; }
}
public class TPM
{
public int Type { get; set; }
public int Id { get; set; }
public Int64 Amount { get; set; }
public int VAT { get; set; }
public DateTime FromDate { get; set; }
public DateTime ToDate { get; set; }
public int CPMCId { get; set; }
}
The data for this List is 5k records of CPMCId and 50k records for each child list inside with condition is
List<int> CPMCIdList = aPP.Select(x => Convert.ToInt32(x.CPMCId)).Distinct().ToList();
List<CPMC> cpl = (from ap in CPMCIdList
select new CPMC
{
CPMCId = ap,
tpm = tpml.Where(x=>x.CPMCId == ap).ToList(),
tpmc = tpmcl.Where(x=>x.CPMCId == ap).ToList()
}).ToList();
But it takes a lot of time to fill data in List. Can you guys have a better implement for this solution
Thanks in advance
Due to the two inner loop linear searches (LINQ Where operators), your current implementation has O(K*N*M) time complexity, where K=CPMCIdList.Count, N=tpml.Count, M=tpmcl.Count.
It can be reduced to the much faster O(K+M+N) by using the LINQ Group Join operators which internally use a quite efficient hash based lookup:
var cpl =
(from cpmcId in CPMCIdList
join tpm in tpml on cpmcId equals tpm.CPMCId into tpmg
join tpmc in tpmcl on cpmcId equals tpmc.CPMCId into tpmcg
select new CPMC
{
CPMCId = cpmcId,
tpm = tpmg.ToList(),
tpmc = tpmcg.ToList()
}).ToList();
First, let's reduce your problem to the minimum case:
You have the following types:
public class A
{
public int Id { get; set; }
public List<B> bs = new List<B>();
public List<C> cs = new List<C>();
}
public class B
{
public int CPMCId { get; set; }
}
public class C
{
public int CPMCId { get; set; }
}
Apparently, you have a list of A's, B's and Cs
List<A> as;
List<B> bs;
List<C> cs;
you're looking to create a list of A's
Now first let's take a look at why your solution is slow.
What you're doing is first creat a list of all the ID's you want, and then, for each ID, search all records that match. That means you're scanning the child lists entirely for every ID. That's clearly not optimal.
The operation you are looking for is called Outer Join in SQL. Unfortunately, Linq doesn't have an equivalent operation out of the box.
So we're going to that ourselves. It's possible to make a generic version of this approach, but it's not entirely straightforward. What we're going to do is sort the A's and the B's by their CPMCId, and then take all the matching records that have a corresponding ID in the list of As:
IEnumerable<A> make_as(IEnumerator<B> ordered_bs, IEnumerator<C> ordered_cs, IEnumerator<int> ordered_ids) {
//make sure the current element of bs and cs is at the first element, not before it.
if(!ordered_bs.MoveNext() || !ordered_cs.MoveNext())
throw new ArgumentException("empty bs or cs");
while(ordered_ids.MoveNext()) {
nextid = ordered_ids.Current;
var a = new A(){
id = nextId;
};
//process the B's
while(ordered_bs.Current.CPMCId < nextid) //not in the list, skip it {
ordered_bs.MoveNext();
}
while(ordered_bs.Current.CPMCId == nextid) //matching, add to the list {
a.bs.add(ordered_cs.Current);
if(!orderd_bs.MoveNext()) break; //move bs forward. If b's is empty, we're done here
}
//do the same for the C's
while(ordered_cs.Current.CPMCId < nextid) {
ordered_cs.MoveNext();
}
while(ordered_cs.Current.CPMCId == nextid) {
a.cs.add(ordered_cs.Current);
if(!ordered_cs.MoveNext()) break;
}
yield return a;
}
}
var result = make_as(
bs.orderBy(b => b.PCMCId).GetEnumerator(),
cs.orderBy(c => c.PCMCId).GetEnumerator(),
as.Select(a => a.id).OrderBy(id => id).Distinct().GetEnumerator()
).ToList()
Some notes:
I'm getting the impression that this is a part of a solution that already had some processing done. When you know that you're going to need all ID's, you don't need the original list of A's at all, and the nextId will be the lowest Current of the A's and Bs
It's also quite possible that right now you're in a bit of a hole you dug yourself in to. It's quite possible that you could do this more efficiently - and more elegantly - further "upstream" in your code.
As a last note, this snippet does not work when either the list of B's or the list of C's contain no elements. In that case, a simple GroupBy is sufficient.

Mapping Linq Group By Results To An Object

I have a class that acts as a summary which is going to be passed to an MVC View as an IEnumerable. The class looks like:
public class FixedLineSummary
{
public long? CustomerId { get; set; }
public string CustomerName { get; set; }
public int? NumberOfLines { get; set; }
public string SiteName { get; set; }
}
The results returned from the db have all of the single entries and so I use linq to summarise these using:
var summary = (from r in result
let k = new {r.CustomerId, CustomerName = r.CompanyName, r.SiteName}
group r by k into t
select new
{
t.Key.CustomerId,
t.Key.CustomerName,
t.Key.SiteName,
Lines = t.Sum(r => r.lines)
});
When I try and cast the results into my object however I just keep getting an error that:
Instance argument: cannot convert from 'System.Linq.IQueryable<AnonymousType#1>' to 'System.Collections.Generic.IEnumerable<Domain.Entities.FixedLineSummary>'
Is there a way to cast the results of the linq query into an enumerable of my class?
You should change the projection to create your class, rather than an anonymous type:
var summary = from r in result
let k = new {r.CustomerId, CustomerName = r.CompanyName, r.SiteName}
group r by k into t
select new FixedLineSummary
{
CustomerId = t.Key.CustomerId,
CustomerName = t.Key.CustomerName,
SiteName = t.Key.SiteName,
NumberOfLines = t.Sum(r => r.lines)
};
You cannot cast the anonymous type to FixedLineSummary since both are not related at all(for the compiler). Instead you need to create instances of your class manually:
IEnumerable<FixedLineSummary> summaries = summary
.Select(s => new FixedLineSummary
{
CustomerId = s.CustomerId,
CustomerName = s.CustomerName,
NumberOfLines = s.NumberOfLines,
SiteName = s.SiteName
})
.ToList();

Categories

Resources