When you query existing linq results, it's like they're stuck a layer deeper than the original result. Let me explain what I mean by this.
In the example below, after getting ResultSorted, to get to the data therein, you have to use RowSorted.All.TableData.Field, but in the unsorted Result, you could just do Row.TableData.Field. In the sorted data, you have to use .All to get to the rest of the data, which is like an extra layer to get to the data you're looking for.
How can I get it so I can query Result without getting this extra layer? Thanks Stack-O!
var Result =
from a in Db.Table
select new {TableData = a};
var ResultSorted =
from a in Result
orderby a.TableData.Field
select new {All = a};
foreach(var RowSorted in ResultSorted)
{
MessageBox.Show(RowSorted.All.TableData.ToString());
}
You can use
var Result =
from a in Db.Table
select a;
var ResultSorted =
from a in Result
orderby a.Field
select a;
foreach(var RowSorted in ResultSorted)
{
MessageBox.Show(RowSorted.ToString());
}
Edit:
The thing is that
select new {TableData = a};
creates a new anonymous type with a field called TableData, like this
class Tmp1
{
TableType TableData {get; set;}
}
and
select new {All = a};
creates a new anonymous type with a field called TableData, like this
class Tmp2
{
Tmp1 All {get; set;}
}
Edit 2:
If you select a directly you don't create the extra anonymous type, instead you return the TableType.
You are returning a new instance of an anonymous type in each of your LINQ queries:
select new {TableData = a};
select new {All = a};
What you are saying to the compiler is (in the first LINQ query), "Give me a new instance of an anoymous type. I want this anonymous type to have one property named TableData and I want the value for that property to be a."
If you simply return a instead of an anoymous type, you shouldn't need to go through the properties of the nested types to get the data. Try this:
var Result =
from a in Db.Table
select a;
var ResultSorted =
from a in Result
orderby a.TableData.Field
select a;
foreach(var RowSorted in ResultSorted)
{
MessageBox.Show(RowSorted.ToString());
}
var ResultSorted =
from a in Db.Table
orderby a.Field
select a.ToString();
Edit: Fixed, didn't see the first query. This should be identical now. There is no need to create anonymous objects all the time.
Related
How would you write "SELECT col.a, col.b FROM TABLE WHERE ID = 1" in LINQ to Entity 6 so that you could save col.a into variable A and col.b into variable B. You can do this with SqlReader by retrieving the index or column name, but with LINQ to Entity it is returned as one object. When returning a two field LINQ query to a list, both field are saved to the first index of the list and can only be accessed as the same list element. Is it standard to create two LINQ queries, one for each variable? Or am I missing part of the process?
Current query:
var result = (from col in cxt.Table
where col.ID == "1"
select new {col.a, col.b}).ToList();
If you are expecting exactly one record to return from database then what you can do:
var result = cxt.Table.FirstOrDefault(x => x.ID == "1");
//Notice that might be null if has not result
var a = result.a;
var b = result.b;
Will look very similar in query syntax but I think this method syntax neater in this case
I am not sure what exactly you are looking for. But selecting two variable by Linq is not so hard.
var value = (from ta in db.YourTable
where ta.ID = id
select new {
A = ta.a,
B = ta.b
}).FirstOrDefault();
var a = value.A;
var b = value.B;
If you use ToList() instead of FirstOrDefault(), you will get a list contain zero or more objects. You can simply use a loop to get field from each object.
forach(var value in values)
{
var a = value.A;
var b = value.B;
}
I've got a table Installation which can contains one or many Equipements.
And for functionnal reasons, I've overwritten my table Installation and added a field NbrEquipements.
I want to fill this field with Linq, but I'm stuck...
Due to special reasons, there is no relation between these to tables. So, no Installation.Equipements member into my class. Therefore, no Installation.Equipements.Count...
I'm trying some stuff. Here is my code:
var query = RepoInstallation.AsQueryable();
// Some filter
query = query.Where(i => i.City.RegionId == pRegionId));
int?[] etatIds = { 2, 3 };
query = (from i in query
select new Installation
{
NbrEquipements= (from e in RepoEquipement.AsQueryable()
where e.InstallationSpecialId == i.SpecialId
&& (etatIds.Contains(e.EquEtat))
select e.SasId
).Count()
});
But with this try, I got this error:
The entity or complex type 'myModel.Installation' cannot be constructed in a LINQ to Entities query
I've tried some other stuff but I'm always turning around...
Another thing that can be useful for me: It would be great to fill a field called Equipements which is a List<Equipement>.
After that, I would be able to Count this list...
Is it possible ?
Tell me if I'm not clear.
Thanks in advance.
Here is the final code:
//In the class:
[Dependency]
public MyEntities MyEntities { get; set; }
//My Methode code:
var query = MyEntities .SasInstallations.AsQueryable();
// Some filter
query = query.Where(i => i.City.RegionId == pRegionId));
var liste = new List<Installation>();
var queryWithListEquipements =
from i in query
select new
{
Ins = i,
EquipementsTemp = (from eq in MyEntities.Equipements.AsQueryable()
where eq.SpecialId == i.SpecialId
&& (etatIds.Contains(eq.SasEquEtat))
select eq
).ToList()
};
var listWithListEquipements = queryWithListEquipements.ToList();
foreach (var anonymousItem in listWithListEquipements)
{
var ins = anonymousItem.Ins;
ins.Equipements = anonymousItem.EquipementsTemp;
ins.NumberEquipements = ins.Equipements.Count();
liste.Add(ins);
}
return liste;
By the way, this is very very fast (even the listing of Equipements). So this is working exactly has I wished. Thanks again for your help everyone!
Use an anonymous type. EF does not like to instantiate entity classes inside a query.
var results = (from i in query
select new
{
NbrEquipements= (from e in RepoEquipement
where e.InstallationSpecialId == i.SpecialId
&& (etatIds.Contains(e.EquEtat))
select e.SasId
).Count()
})
.ToList();
Notice how I used select new instead of select new Installation.
You can then use the data inside the list (which is now in memory) to create instances of type Installation if you want like this:
var installations = results.Select(x =>
new Installation
{
NbrEquipements = x.NbrEquipements
}).ToList();
Here is how to obtain the list of equipment for each installation entity:
var results = (from i in query
select new
{
Installation = i,
Equipment = (from e in RepoEquipement
where e.InstallationSpecialId == i.SpecialId
&& (etatIds.Contains(e.EquEtat))
select e).ToList()
})
.ToList();
This will return a list of anonymous objects. Each object will contain a property called Installation and another property called Equipment (which is a list). You can easily convert this list (of anonymous objects) to another list of whatever type that you want.
I try Get 5 Object in each group to display.
I tried code like this:
var BBS = (from bb in db.Object
where SubjectList.Contain(bb.Type)
select new ObjectModel {
Subject = bb.Subject,
CDate = bb.CDate
}).GroupBy(a => a.BBSTypeSubject).Take(5);
but it doesn't work.
and then I try it by using Foreach
First off, realize that C# is case sensitive, so you need to spell function names like Take and Contains correctly. But you can solve this problem fairly easily by just using this overload of GroupBy instead.
var BBS = (from bb in db.Object
where SubjectList.Contains(bb.Type)
select new ObjectModel {
Subject = bb.Subject,
CDate = bb.CDate
}).GroupBy(a => a.BBSTypeSubject, (k, g) => g.Take(5));
The second parameter allows you to specify what result object will be returned for each group. In this case, I simply take the first 5 items from the group and return those instead.
When you select new ObjectModel, there's no property called BBSTypeSubject. You need to include that. So it should be
select new ObjectModel {
Subject = bb.Subject,
CDate = bb.CDate,
BBSTypeSubject= ???
}
I am getting values from different tables i var type and I want to return them. What should be the return type of the function:-
public void getlist()
{
try
{
using (ShowDataToClientDataContext c = new ShowDataToClientDataContext())
{
var recList = (from record in c.GetTable<T_RECORDSHOW>()
where record.RecordStatus.Equals(RecordStatus.Active)
select new
{
Student = (from stu in c.T_STUDENTSHOWs
where stu.Id.Equals(record.StudentId)
select stu.Name).Single().ToString(),
Trade = (from t in c.T_TRADESHOWs
where t.Id.Equals(record.TradeId)
select t.Name).Single().ToString(),
SessionId = (from s in c.T_SESSIONSHOWs
where s.Id.Equals(record.SessionId)
select s.Name).Single().ToString(),
Month = record.Month.ToString(),
Attendance = record.Attendance.ToString(),
}).ToList();
return recList;
}
}
catch
{
}
}
anybody there to help me?
var isn't a type in itself. It just asks the compiler to infer the type of the local variable.
Now in your case, the type is a List<T> where the T is an anonymous type. If you want to be able to use the properties within the elements of the list from other code, you'll need to either do so dynamically (ick) or turn the anonymous type into a full, named type. Anonymous types are really only designed to be used from the methods where the objects are created. You can then return a List<DenormalizedRecord> or whatever.
Also note that your query would be much simpler if you'd just use joins:
from record in c.GetTable<T_RECORDSHOW>()
where record.RecordStatus.Equals(RecordStatus.Active)
join student in c.T_STUDENTSHOWs on record.StudentId equals student.Id
join trade in c.T_TRADESHOWs on record.TradeId equals trade.Id
join session in c.T_SESSIONSHOWs on record.SessionId equals session.Id
select new DenormalizedRecord {
Student = student.Name,
Trade = trade.Name,
SessionId = session.Name, // Confusing property name, by the way
Month = record.Month.ToString(), // Why the ToString()?
Attendance = record.Attendance.ToString() // What the ToString()?
}
It's not totally true that you cannot return anonymous types from a method, and I don't mean using tricky stuff with reflection. You just have to move the burden of instantiation to the caller:
IEnumerable<T> getlist<T>(Func<string, string, string, string, string, T> resultor)
{
try
{
using (ShowDataToClientDataContext c = new ShowDataToClientDataContext())
{
var recList = (from record in c.GetTable<T_RECORDSHOW>()
where record.RecordStatus.Equals(RecordStatus.Active)
select resultor
(
(from stu in c.T_STUDENTSHOWs
where stu.Id.Equals(record.StudentId)
select stu.Name).Single().ToString(),
(from t in c.T_TRADESHOWs
where t.Id.Equals(record.TradeId)
select t.Name).Single().ToString(),
(from s in c.T_SESSIONSHOWs
where s.Id.Equals(record.SessionId)
select s.Name).Single().ToString(),
record.Month.ToString(),
record.Attendance.ToString()
)).ToList();
return recList;
}
}
catch
{
}
}
Type inference works like a charm, so you can call your method like this:
var list = getlist((st, tr, sid, m, att) => new
{
Student = st,
Trade = tr,
SessionId = sid,
Month = m,
Attendance = att
});
No need to define any DTO class just for the sake of outputting those results.
PS: the query itself could be better, but I'm just tackling the problem in your question.
You can't return an anonymous type from a method (perhaps with some very technical workarounds).
You should probably create a class with the properties that you want returned, and then return an object of that class.
Create a custom class. Use it as return type
select new CustomClass
{
Propery1 = YourSelectedPropery1
, Propery2 = YourSelectedPropery2
}
I've noted that you can use some generic parameter in order to solve your problem.
Change method signature to:
public List<TReturn> getlist<TReturn>()
And change your ToList<ClassName>() to ToList<TReturn>.
This will enable your method to return lists of any type (supported by your model, of course!).
The columns names and types are identical, however it's coming from two separate entities. Here is a simplified example:
--Query View
var v_res = from s in db.V_CMUCUSTOMER
select s;
--Values from table less values from view
var res = from s in db.CMUCUSTOMERs
where !(from v in v_res
select v.ID).Contains(s.ID)
select s;
--join table and view values into one variable
var res_v_res = (from c in res
select c).Union(from v in v_res
select v);
I get the following error however:
Instance argument: cannot convert from 'System.Linq.IQueryable' to System.Linq.ParallelQuery
If you specify a new anonymous type and use ToList() for both then you should be able to Union them as follows :
var v_res = (from s in db.V_CMUCUSTOMER
select new { custName = s.customer_name custAddress = s.address}).ToList();
--Values from table less values from view
var res = (from s in db.CMUCUSTOMERs
where !(from v in v_res
select v.ID).Contains(s.ID)
select new { custName = s.customer_name custAddress = s.address }).ToList();
--join table and view values into one variable
var res_v_res = v_res.Union(res);
This may be onerous if there are dozens of columns but should still work.
When I run a similar query in LINQPad, I get an error message claiming that s in Contains(s.ID) is not defined in this context.
If I replace && with where all queries are successfully executed.