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.
Related
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
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.
My code like bellow:
This Main class :
public class Product {
public string Id { set; get; }
public IList<Attr> Attributes { set; get; }
}
This child class of main class :
public class Attr
{
public string Key { set; get; }
public object Value { set; get; }
}
Filter item class:
public class Filter
{
public CompareType Type { set; get; }
public string Key { set; get; }
public object Value { set; get; }
}
Linq extension fuction for querying :
public static class LINQExtension
{
public static bool isMatch(this Product prod, this List<Filter> filters)
{
foreach(Filter F in filters){
Attr attribute = prod.Attributes.Any(A => A.Key == F.Key);
switch(F.Type){
case CompareType.CONTAIN: return ((string)attribute.Value).Contains(F.Value);
case ....
default: return false;
}
}
}
}
Filtering products result: (Not working)
public ActionResult FilterProducts(string word, decimal min, decimal max){
List<Filter> Conditions = new List<Filter> {
new Filter {Key = "Price", Type = CompareType.BETWEEN, Value = new decimal[] {min, max} },
new Filter {Key = "Title", Type = CompareType.CONTAIN, Value = word }
...
};
var Result = Session.Query<Product>().Where(P => P.isMatch(Conditions)).ToList();
return View(Result);
}
When it tried to run give errors like below:
{"Could not understand expression: .Where(P => P.isMatch(value(App.Controllers.HomeController+<>c__DisplayClass2).Conditions)).ToList()"}
In general, RavenDB's linq provider implementation is not equal to Linq-to-Objects provider.
Under the hood, Raven's client API serializes linq query experssion to Lucene query, then makes a REST call to server with that query. (You can use Fiddler to see it happen)
For example, given a database named Test with Northwind sample data and the query code (and assuming you have Fiddler active)
using (var store = new DocumentStore
{
Url = "http://localhost.fiddler:8080",
DefaultDatabase = "Test"
})
{
store.Initialize();
using (var session = store.OpenSession())
{
var result = session.Query<Order>().Where(x =>
x.Company == "companies/58" && x.Freight < 30m).ToList();
}
}
you will see the following REST call to the server (after url decoding)
http://localhost:8080/databases/Test/indexes/dynamic/Orders?&query=Company:companies/58 AND Freight_Range:{* TO Dx30}&pageSize=128&SortHint-Freight_Range=Double
What you see highlighted in the url is Linq query "serialized" into Lucene query.
In your case the error that you are seeing is simply Raven's linq implementation cannot understand how to transform your custom code into Lucene query
I have this Linq query on my Controller which will give me an object in a List and I need to pass this object to a function, that is in another class, which will consume it.
This is my Linq query:
var cursos = (from c in db.Curso
join cc in db.CursoCategoria on c.cursoCategoriaId equals cc.ID
where c.ativo == 1 && c.destaque == 1
select new { ID = c.ID,
nome = c.nome,
imgAbre = c.imagemAbre,
imgFecha = c.imagemEfeito,
cURL = c.URL,
ccURL = cc.URL,
cCor = cc.cor}).Take(10).ToList();
This is how I call the function:
var objHelper = new HelperController();
siteVM.lstCursosWall = Json(objHelper.MontaWallCurso());
This is my function in HelperController, this class is also a Controller, I have it as this because I have several helper functions and ajax methods for the project:
public string MontaWallCurso()
{
//TODO STUFF
}
So, how can I pass this object if I don't have a type?
Note: I'm using a DAL model that I create from my database using EF, don't know if this is useful.
EDIT
So I change my method and created a class to populate and transfer the data, but now I'm having problems passing the linq result to the object.
var siteVM = new SiteViewModel();
var cursos = new List<CursoWall>();
var lCursos = (from c in db.Curso
join cc in db.CursoCategoria on c.cursoCategoriaId equals cc.ID
where c.ativo == 1 && c.destaque == 1
select new { ID = c.ID,
nome = c.nome,
imgAbre = c.imagemAbre,
imgFecha = c.imagemEfeito,
cURL = c.URL,
ccURL = cc.URL,
cCor = cc.cor}).Take(10).ToList();
cursos.AddRange(lCursos);
The class:
public class CursoWall
{
public int ID { get; set; }
public string nome { get; set; }
public string imgAbre { get; set; }
public string imgFecha { get; set; }
public string cURL { get; set; }
public string ccURL { get; set; }
public string cCor { get; set; }
}
You cannot. You need to define a simple 'Poco' type for DTO for data transfer in this case.
http://rlacovara.blogspot.nl/2009/03/what-is-difference-between-dto-and-poco.html
If you are willing to sacrifice type safety, you could use C#'s dynamic support.
public string MontaWallCurso(IList<dynamic> cursos) {
// use dynamic properties or something that takes dynamic arguments
foreach( dynamic curso in cursos ) {
curso.SomePropertyYouAreSureExists = 1;
curso.SomeMethodYouAreSureExists();
}
}
Alternatively, if you are willing to sacrifice type safety and deal with the trouble, you could use reflection. There are some cases where you can do this indirectly, e.g. a JSON converter or other reflection-reliant library code.
public string MontaWallCurso(IList<object> cursos) {
// use reflection or something that uses reflection itself
foreach( object curso in cursos ) {
Type cursoType = curso.GetType();
cursoType.GetProperty("SomePropertyYouAreSureExists").SetValue( curso, 1 );
cursoType.GetProperty("SomeMethodYouAreSureExists").Invoke( curso, null );
}
}
To clarify, of these approaches, the only one that I would likely recommend is the library-based reflection one if it's applicable.
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())
};