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.
Related
I want to join 3 tables form their contexts with linq or lambda but I get an error.
This is my linq
enter image description here
public async Task<IEnumerable<TblCharityAccount>> GetAccountasync()
{
BaseData_Contexts db1 = new BaseData_Contexts();
BaseType_Context db2 = new BaseType_Context();
var joined = (from ep in _db.TblCharityAccounts
join e in db1.TblCommonBaseData on ep.BankId equals e.CommonBaseDataId
join c in db2.TblCommonBaseTypes on e.CommonBaseTypeId equals c.CommonBaseTypeId
select new
{
c.BaseTypeTitle,
c.BaseTypeCode,
c.CommonBaseTypeId,
e.BaseCode,
e.BaseValue,
e.CommonBaseDataId
});
return joined;
}
Error:
Cannot implicitly convert type 'System.Linq.IQueryable<<anonymous type: string BaseTypeTitle, string BaseTypeCode, int CommonBaseTypeId, string BaseCode, string BaseValue, int CommonBaseDataId>>' to 'System.Collections.Generic.IEnumerable<CharityAccounts.Model.TblCharityAccount>'.
You are returning Task<IEnumerable<TblCharityAccount>> however joined consists of a list of anonymous types. I added a ToList() not sure exactly if this is what you wanted but i'm assuming this is entity framework and entity framework is deferred execution. Also you have not provided if TblCharityAccount fits the same bill as your anonymous type so you may need to create a new type for this.
public class JoinTableResult
{
public string BaseTypeTitle { get ; set; }
public string BaseTypeCode { get ; set; }
public string CommonBaseTypeId { get ; set; }
public string BaseCode { get ; set; }
public string BaseValue { get ; set; }
public string CommonBaseDataId { get ; set; }
}
public async Task<IEnumerable<JoinTableResult>> GetAccountasync()
{
BaseData_Contexts db1 = new BaseData_Contexts();
BaseType_Context db2 = new BaseType_Context();
var joined = (from ep in _db.TblCharityAccounts
join e in db1.TblCommonBaseData on ep.BankId equals e.CommonBaseDataId
join c in db2.TblCommonBaseTypes on e.CommonBaseTypeId equals c.CommonBaseTypeId
select new
{
c.BaseTypeTitle,
c.BaseTypeCode,
c.CommonBaseTypeId,
e.BaseCode,
e.BaseValue,
e.CommonBaseDataId
}).ToList();
return joined;
}
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.
I am using .NET 4.6 and I am trying to create a specific list from a generic one. Code(the generic list):`
var clients = (from a in accounts
group j by new
{
a.Code,
a.Name,
a.AddressLine1,
a.Postcode,
a.City,
}
into g
select new
{
g.Key.Code,
g.Key.Name,
g.Key.AddressLine1,
g.Key.PowerTools,
g.Key.Internetportal,
g.Key.Huisvestingsplanning,
g.Key.Werkplanning,
g.Key.Vervoersplanning
}).ToList();
The specific List(Customer.cs):
struct Customer
{
public string Code { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public double PowerTools { get; set; }
public double Internetportal { get; set; }
public double Huisvestingsplanning { get; set; }
public double Werkplanning { get; set; }
public double Vervoersplanning { get; set; }
}
Conversion:
customers = clients.Cast<List<object>>().Select(x => new Customer(){
Code = (string)x[0],
Name = (string)x[1],
Address = (string)x[2],
PowerTools = (double)x[3],
Internetportal = (double)x[4],
Huisvestingsplanning = (double)x[5],
Werkplanning = (double)x[6],
Vervoersplanning = (double)x[7]}).ToList();
The error this conversion throws:
Unable to cast object of type '<>f__AnonymousType68 [System.String,System.String,System.String,System.Double,System.Double,System.Double,System.Double,System.Double]' to type 'System.Collections.Generic.List1[System.Object]'.
Thanks
Your code appears to be trying to convert some object into a list of its properties - this isn't going to work, C# isn't JavaScript. It's doable, but completely unnecessary.
What you really need is to just use the anonymous type in the way it's meant to be used:
clients.Select(x => new Customer { Code = x.Code, Name = x.Name, ... }).ToList();
Depending on the actual LINQ provider you're using, it might even be possible to skip the middle man and select directly into your own type - consult the documentation.
Also, just for clarity - both of those lists are generic. The difference is that the first one is a generic list of an anonymous type, while the second one is a generic list of a named type.
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())
};
The following LINQ:
retval = ( from jm in entities.JobMasters
where jm.UserId == userId && jm.IsRemote == false
select new JobDto
{
JobMasterId = jm.JobMasterId,
ExternalTaskId = jm.ExternalTaskId,
JobDetails = ( from jd in entities.JobDetails
where jd.JobMasterId == jm.JobMasterId
select new JobDetailDto { ScreenFieldId = jd.ScreenFieldId, FieldValue = jd.FieldValue }
).ToList()
}
).ToList();
is giving me this error:
LINQ to Entities does not recognize the method
'System.Collections.Generic.List`1[KernWcfTest.DataTransferObjects.JobDetailDto]
ToList[JobDetailDto](System.Collections.Generic.IEnumerable`1[KernWcfTest.DataTransferObjects.JobDetailDto])' method,
and this method cannot be translated into a store expression.
Here are the two dto classes:
[DataContract]
public class JobDetailDto
{
[DataMember]
public int ScreenFieldId { get; set; }
[DataMember]
public string FieldValue { get; set; }
}
[DataContract]
[KnownType(typeof(JobDetailDto))]
public class JobDto
{
[DataMember]
public int JobMasterId { get; set; }
[DataMember]
public string ExternalTaskId { get; set; }
[DataMember]
public List<JobDetailDto> JobDetails { get; set; }
}
The problem is the sub-select and the JobDetails list. I tried adding the KnownType but it didn't work.
This all works fine in LINQ Pad.
Any ideas?
Cheers
Steve
Don't call ToList on the inner query (the one for JobDetails). The error is "This .ToList method you speak of -- it can't be translated to T-SQL!"
This should work:
retval = ( from jm in entities.JobMasters
where jm.UserId == userId && jm.IsRemote == false
select new JobDto
{
JobMasterId = jm.JobMasterId,
ExternalTaskId = jm.ExternalTaskId,
JobDetails = from jd in entities.JobDetails
where jd.JobMasterId == jm.JobMasterId
select new JobDetailDto { ScreenFieldId = jd.ScreenFieldId, FieldValue = jd.FieldValue }
)
}
).ToList();
Note that you can call ToList on the end of the query, as that part doesn't need to be translated to T-SQL.