I am having problem with converting the DateTime I am collecting from the database to localtime with LINQ. A LINQ query won't let me use ToLocalTime() and I can't seem to get any fix outside the query to work with the anonymous type of list.
Here is the LINQ query from the controller :
// GET: api/Scan
public object Getv_Update_ComplianceStatusAll()
{
var dato = DateTime.Now.AddYears(-1);
var scan = (from n in db.C_RES_COLL_NO9000AC
join s in db.v_Update_ComplianceStatusAll on n.MachineID equals s.ResourceID
join u in db.v_UpdateInfo on s.CI_ID equals u.CI_ID
join c in db.v_CICategoryInfo on u.CI_ID equals c.CI_ID
where (n.MachineID == s.ResourceID) && (u.DateRevised > dato)
group s by new { n.Name } into grp
select new
{
Name = grp.Key.Name,
StatusScan = grp.Max(t=> t.LastStatusCheckTime)
});
return scan;
}
This is my attemt at a fix outside the query :
var newScan = scan.ToList();
foreach (var s in newScan)
{
s.StatusScan = s.StatusScan.ToLocalTime();
}
return newScan;
The converstion works, but it returns "Error 306 Property or indexer 'AnonymousType#1.StatusScan' cannot be assigned to -- it is read only"
So, how do I convert the UTC to local time in the controller (before I return anything to the website)?
Yes, Anonymous Type is handy, but it is a bad idea to return it from a method -- Outsider do not know what actually the object is. It is recommended to create a strong type to store the result and return IEnumerable<ScanItem>. Then you are able to modify the result.
public class ScanItem
{
public string Name { get; set; }
public datetime StatusScan { get; set; }
}
If you must use Anonymous Type, You can build a new list like this
scan.ToList().Select(i => new {Name = i.Name, StatusScan = i.StatusScan.ToLocalTime()});
var newScan = scan.ToList();
foreach (var s in newScan)
{
s.StatusScan = s.StatusScan.ToLocalTime();
}
return newScan;
your newScan is a List, you cannot directly assign
s.StatusScan = s.StatusScan.ToLocalTime();
Related
I have this code:
public class ExistedProducts
{
public int productID{get;set;}
public int productQte{get;set;}
}
..
..
..
public List<ExistedProducts> GetStock()
{
var result = from p in Products
join st in Stock on st.ProductID equals p.ID
select new{ExistedProductID=p.ID,ExistedProductQte = st.Qte};
return result.Cast<ExistedProducts>.ToList();// exception here
}
My first question, can I directly produce the typed collection from the query?
If not, how can I do the casting (i called the Cast() method but a raised exception saying impossible to do cast from
'<>f__AnonymousType0`2[System.Int32,System.Int32] ?
I want to avoid the copy by loop!
Yes instead of projecting anonymous type you can directly project your type ExistedProducts like this:-
var result = (from p in Products
join st in Stock on st.ProductID equals p.ID
select new ExistedProducts
{
productID = p.ID,
productQte = st.Qte
}).ToList();
return result;
I have this piece of code
var myList = (from p in db.Full
where ((p.date_reception > begin & p.date_reception < end & !p.mc_host_class.Contains("NULL")) &
(!strListe.Contains(p.mc_host_class)))
group p by p.mc_host_class into g
orderby g.Count() descending
select new
{
hostclassx = g.Key,
countx = g.Count()
}).Take(10).ToList();
HttpContext.Current.Session["allList"] = myList;
i want to get two type of values from my session variable , before using session variable i used to do
object[] ys = myList.Select(a => (object)a.countx.ToString()).ToArray();
List<String> xs = new List<string>();
foreach (var x in myList.Select(i => i.hostclassx))
{
xs.Add(x);
}
I want to get the same type of variables(xs and ys) from my session variable
You have stored an anonymous object inside the session. Anonymous objects are not intended to be leaving the boundaries of the current method. So start by defining a model:
public class MyModel
{
public string HostClass { get; set; }
public int Count { get; set; }
}
and then project your query into this object (bear in mind that you might need to adjust the type of the HostClass property according to your needs - I have defined it as a string but in your particular model it might be some other type, it's just not clear what types of objects are involved in your queries from the code you have pasted so far):
...
orderby g.Count() descending
select new MyModel
{
HostClass = g.Key,
Count = g.Count()
}).Take(10).ToList();
Alright, now you've got a List<MyObject> stored inside your Session["allList"]. So in order to retrieve this value somewhere else in your code it's just a matter of casting back to this same type:
var list = (List<MyModel>)HttpContext.Current.Session["allList"];
And as a side note you seem to be using a & operator instead of && in your where predicates, maybe you didn't exactly wanted to use this. You seem to be confusing the logical AND operator and the binary AND operator.
I am grabbing a value and want it to appear in the BatchId of every anonymous type created via a linq statement.
Here is the code:
var batchId = context.Request["batchid"];
using (var db = new StarterSiteEntities())
{ // Get data
var transactions = (from t in db.Transactions
join td in db.TransactionDetails on t.TransactionID equals td.TransactionID
join p in db.Products on td.ProductID equals p.ProductID
where t.Exported == false
select new
{
BatchId = batchId,
t.FirstName,
t.LastName,
t.Address1,
t.Address2,
t.City,
t.State,
t.Zip_Code,
t.Email,
t.Phone,
t.TotalAmount,
t.MonthlyGift,
t.DateCreated,
p.Fund,
ProductFirstName = p.FirstName,
ProductLastName = p.LastName,
ProductUniversity = p.University,
ProductState = p.State,
ProductEmail = p.Email,
ProductAmount = td.Amount
}).ToList();
}
When I do this, I get the error message:
"A parameter is not allowed in this location. Ensure that the '#' sign is in a valid location or that parameters are valid at all in this SQL statement."
How do I reference the batchId variable from within the anonymous type declaration, or should I accomplish this another way?
It looks like you ran into a known bug in the SQL Server CE data access libraries. You should be able to fix it by applying this hotfix to the machine(s) that are accessing the database.
While I think Adam Maras answered my question. Because I did not want to install a hot-fix on the server, I ended up solving the problem using a different method.
Since the Linq query would not allow me to use a string variable and I could not edit the property value of an anonymous type. I stopped using an anonymous type and created an entity class to hold my "transaction summary" data.
Once I have a collection of TransactionSummary objects, I can use the Select() method to update the BatchId property value in each record.
Here is the resulting code:
// Define a custom type to hold the data
private class TransactionSummary
{
public string BatchId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
//...removed lines for brevity...
}
//...here is the updated code snippet...
using (var db = new StarterSiteEntities())
{ // Get data
var transactions = (from t in db.Transactions
join td in db.TransactionDetails on t.TransactionID equals td.TransactionID
join p in db.Products on td.ProductID equals p.ProductID
where t.Exported == false
select new TransactionSummary
{
FirstName = t.FirstName,
LastName = t.LastName,
//...removed lines for brevity...
}).ToList();
// The client would like a batchID added to each record that we return.
var batchId = context.Request["batchid"];
transactions.Select(t => { t.BatchId = batchId; return t; }).ToList();
}
Below is my LINQ Query, that im using to select ITEMS:
protected void Page_Load(object sender, EventArgs e)
{
whatsmydiscountEntities ctx = new whatsmydiscountEntities();
int IdRelationshipItems = Convert.ToInt32(Request.QueryString["IdRelationshipItems"]);
int IdProductService = Convert.ToInt32(Request.QueryString["IdProductService"]);
var Items = (from es in ctx.State
join ie in ctx.ItemsStates on es.StateId equals ie.StateId
join i in ctx.Items on ie.IdItem equals i.IdItem
join iir in ctx.ItemsRelationshipItems on i.IdItem equals iir.IdItem
join ir in ctx.RelationshipItems on iir.IdRelationshipItems equals ir.IdRelationshipItems
join ips in ctx.ItemsProductsServices on i.IdItem equals ips.IdItem
join ps in ctx.ProductsServices on ips.IdProductService equals ps.IdProductService
where iir.IdRelationshipItems == IdRelationshipItems
&& ips.IdProductService == IdProductService
&& ir.Active == 1
&& i.Active == 1
select new
{
ItemName = i.Name,
StateSigla = es.Sigla,
ProductServiceName = ps.Ttitle,
RelationshipItemName = ir.Name,
RelationshipItemImage = ir.Image,
RelationshipItemActive = ir.Active,
ItemSite = i.Site,
ItemDescription = i.Description,
ItemAddress = i.Address,
Iteminformationdiscount = i.information_discount,
ItemLogo = i.Logo,
ItemActive = i.Active,
StateId = ie.StateId,
IdRelationshipItems = iir.IdRelationshipItems,
IdProductService = ips.IdProductService
}).ToList();
}
As you can see, the result will be 1 row for each state, if the user passes the IdRelationshipItems and the IdProductService.
Instead of 1 row for each state with the same information, I'd like to show only 1 row and all the states separated by commas. What do I need to change to do this?
I had to solve this problem today. I have a view model that looks like this:
public class IndexViewModel
{
public string Search { get; set; }
public IPagedList<MembershipUser> Users { get; set; }
public IEnumerable<string> Roles { get; set; }
public bool IsRolesEnabled { get; set; }
public IDictionary<string,string> Tags { get; set; }
}
I needed to return a unique list of users and all of the Tags that are assigned to them as a comma separated string.
The data is stored like this:
"41FFEC0F-B920-4839-B0B5-862F8EDE25BD", tag1
"41FFEC0F-B920-4839-B0B5-862F8EDE25BD", tag2
"41FFEC0F-B920-4839-B0B5-862F8EDE25BD", tag3
And I needed output that looked something like this:
"41FFEC0F-B920-4839-B0B5-862F8EDE25BD", "tag1, tag2, tag3"
I ended up creating a List of UserId's like this (I'm using the MembershipProvider which exposes the UserId as ProviderUserKey):
var userIdList = users.Select(usr => (Guid) usr.ProviderUserKey).ToList();
The object "users" is a MembershipUser object. I then call a function in my service passing the List in like this:
Tags = _usersTagsService.FindAllTagsByUser(userIdList)
And my service function looks like this:
public IDictionary<string, string> FindAllTagsByUser(IList<Guid> users)
{
var query = (from ut in _db.UsersTags
join tagList in _db.Tags on ut.TagId equals tagList.Id
where users.Contains(ut.UserId)
select new {ut.UserId, tagList.Label}).ToList();
var result = (from q in query
group q by q.UserId
into g
select new {g.Key, Tags = string.Join(", ", g.Select(tg => tg.Label))});
return result.ToDictionary(x=>x.Key.ToString(),y=>y.Tags);
}
I'm pretty sure these two linq statements can probably be combined into one but I find it easier to read this way. Still only hits the database once.
Things to watch out for:
I was originally passing just IList users into the function FindAllTagsByUser and linq couldn't infer the type and therefore wouldn't let me use the .Contains extension method. Kept saying that linq to entities didn't support Contains.
You need to do a .ToList() on the first query to materialize it or you will get trouble from linq to entity when you try to use string.Join to create the comma separated list.
Good luck
dnash
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!).