SPFieldLookupValue in Linq Query - linq

I'm trying to the the value of a lookup field in SharePoint using Linq and a collection of SPListItem - something like this:
int totalDepts = (from SPListItem itm in hourEntries select ((SPFieldLookupValue)itm["Level1"]).LookupValue).Distinct().Count();
But that doesn't seem to work (and it strikes me as missing some steps)
Has anyone done this before?

I wasn't able to figure out to do it directly in the Linq query, so I ended up creating WorkHoursEntries object, and populating it with all my SPListItems
List<WorkHourEntry> workHourEntries = new List<WorkHourEntry>();
foreach (SPListItem hourEntry in hourItems)
{
//Collect entries that are in the current Fiscal Year reporting period
if (fiscalYearMonths.Contains(hourEntry["Reporting_x0020_Month"].ToString()))
{
WorkHourEntry curEntry = new WorkHourEntry();
string Level1 = (string)hourEntry["Level1"];
SPFieldLookupValue val = new SPFieldLookupValue(Level1);
curEntry.organization = val.LookupValue;
SPFieldCalculated cf = (SPFieldCalculated)hourEntry.Fields["WECSCHours"];
curEntry.WECSCHours = cf.GetFieldValueForEdit(hourEntry["WECSCHours"]);
workHourEntries.Add(curEntry);
}
}
This allowed me to run Linq queries directly on the WorkHourEntry collection
var uniqueDeptNames = (from itm in workHourEntries select itm.organization).Distinct().ToArray();

Related

I need most complicated query

I use Linq to Sql.
I have three table.
tabl_Region: from this table returning .ToList() via county column == 85
tabl_Season: from this table returning .ToList() via startdate >= today
tabl_Desc: from this table returning int [] ID via fldRegion== 1 results && fldSeason== 2 results
I will try to explain not worked codes
TurkusEntities context = new TurkusEntities();
return context.tabl_AttrDesc.Where(c => c.fldRegionId == context.tabl_Region.Where(r => r.fldCounty == 85).ToList() && c.fldSeasonId == context.tabl_Season.Where(s => s.fldStartDate >= DateTime.Now).ToList()).ToList;
I know i can solve it by using loops, but if it is possible i want to use only query.
If you are using Linq2Sql you can get the
sql that is generated by a linq query. with this command.
dc.GetCommand(query).CommandText
If you are using SQL Server Profiler inside the Sql Server (Tools --> SQL Server Profiler)
I found solution but not impossible in one query.
First I got int [] ID arrays which match conditions from two tables.After I wrote a query which provide control column data from arrays.
TurkusEntities context = new TurkusEntities();
Region region = new Region();
string[] dataarray = region.GetAllRegionsBySomeRule(RegionX);
var _db= context.tabl_AttrDesc.Where(c =>dataarray.Contains(c.fldRegionId.ToString().Trim())).ToList();
And Region
public string[] GetAllRegionsBySomeRule(int fldType,int fldRegionX)
{
TurkusEntities context = new TurkusEntities();
var _db = context.tabl_Region.Where(c => c.fldTown.Contains(fldRegionX.ToString())).ToList();
foreach (var data in _db)
{
Regions.Add(data.fldId.ToString().Trim());
}
string[] IDS = Regions.ToArray();
return IDS;
}

Get Date part Using LINQ

I have four tables, with Date data type for the fields startingDate, EndingDate, and ApplyingDate.
I am using ADO.net Entity Framework.
I have written the following query to get the results, but I am getting the dates with the time, and I want only the date part.
I have used EntityFunctions.TuncateTime, but I am still getting same results.
Could anyone please suggest me, how to Get the date only ?
var leaveList = (from application in db.tbl_ApplicationData
join employee in db.tbl_EmployeeDetails
on application.UserName equals employee.UserName
join leaveType in db.tbl_LeaveType
on application.LeaveTypeId equals leaveType.LeaveTypeId
join status in db.tbl_Status
on application.ApplicationStatusId equals status.StatusId
where application.UserName == "100083"
select new
{
EmployeeName = employee.EmployeeName,
LeaveTypeID = leaveType.LeaveTypeName,
StartingDate = EntityFunctions.TruncateTime(application.StartingDate),
EndingDate = EntityFunctions.TruncateTime(application.EndingDate),
AppliedDate = EntityFunctions.TruncateTime(application.ApplyingDate),
NoOfDays = application.NoOfDays,
LeavePurpose = application.LeavePurpose,
LeaveStatus = status.StatusName
});
If your entity model is a System.DateTime, you can just use the DateTime methods when you are using your object:
select new {
EndingDate = application.EndingDate
};
var myValue = leaveList.EndingDate.Date;
Or if you want a string:
leaveList.EndingDate.ToShortDateString()

Linq query select count into same entity

I got two tables: comments and commentLikes
in the same query i count the likes users have given on a comment.
I got the following (simplified) query:
var res = (from c in db.Comments
where c.Topic.ID == topicID
select new
{
comment = c,
count = c.CommentLikes.Count()
}).ToList();
But, rather than mapping the likecount into the comment entity again, I'd like to get a list of Comments only with a field LikeCount in it, preferably with an efficient query. Something like this:
var res = (from c in db.Comments
where c.Topic.ID == topicID
select new
{
comment = c,
c.LikeCount = c.CommentLikes.Count()
}).ToList();
This query doesn't compile.
How to do this in linq?
You can't do that. EF does not support to project (= select) data into an entity. You must fill the LikeCount property in memory after the query has been executed. You can write it in a compact way, but it's basically just a foreach loop over the materialized anonymous objects:
IEnumerable<Comment> res =
(from c in db.Comments
where c.Topic.ID == topicID
select new
{
comment = c,
count = c.CommentLikes.Count()
})
.ToList() // DB query runs here, the rest in memory
.Select(a => {
a.comment.LikeCount = a.count;
return a.comment;
});

LINQ to Entities does not recognize the method 'System.String Format(System.String, System.Object, System.Object)'

I have this linq query:
private void GetReceivedInvoiceTasks(User user, List<Task> tasks)
{
var areaIds = user.Areas.Select(x => x.AreaId).ToArray();
var taskList = from i in _db.Invoices
join a in _db.Areas on i.AreaId equals a.AreaId
where i.Status == InvoiceStatuses.Received && areaIds.Contains(a.AreaId)
select new Task {
LinkText = string.Format(Invoice {0} has been received from {1}, i.InvoiceNumber, i.Organisation.Name),
Link = Views.Edit
};
}
It has issues though. I'm trying to create tasks. For each new task when I set the link text to a constant string like "Hello" it is fine. However above I'm trying to build the property linktext using properties of the invoice.
I get this error:
base {System.SystemException} = {"LINQ to Entities does not recognize the method 'System.String Format(System.String, System.Object, System.Object)' method, and this method cannot be translated into a store expression."}
Anyone know why? Anyone know an alternative way of doing this to make it work?
Entity Framework is trying to execute your projection on the SQL side, where there is no equivalent to string.Format. Use AsEnumerable() to force evaluation of that part with Linq to Objects.
Based on the previous answer I have given you I would restructure your query like this:
int statusReceived = (int)InvoiceStatuses.Received;
var areaIds = user.Areas.Select(x=> x.AreaId).ToArray();
var taskList = (from i in _db.Invoices
where i.Status == statusReceived && areaIds.Contains(i.AreaId)
select i)
.AsEnumerable()
.Select( x => new Task()
{
LinkText = string.Format("Invoice {0} has been received from {1}", x.InvoiceNumber, x.Organisation.Name),
Link = Views.Edit
});
Also I see you use related entities in the query (Organisation.Name) make sure you add the proper Include to your query, or specifically materialize those properties for later use, i.e.:
var taskList = (from i in _db.Invoices
where i.Status == statusReceived && areaIds.Contains(i.AreaId)
select new { i.InvoiceNumber, OrganisationName = i.Organisation.Name})
.AsEnumerable()
.Select( x => new Task()
{
LinkText = string.Format("Invoice {0} has been received from {1}", x.InvoiceNumber, x.OrganisationName),
Link = Views.Edit
});
IQueryable derives from IEnumerable, the main resemblance is that when you make your query it is posted to the database engine in it's language, the thin moment is where you tell C# to handle the data on the server(not client side) or to tell SQL to handle data.
So basically when you say IEnumerable.ToString(), C# gets the data collection and calls ToString() on the object.
But when you say IQueryable.ToString() C# tells SQL to call ToString() on the object but there is no such method in SQL.
The drawback is that when you handle data in C# the whole collection that you are looking through must be built up in memory before C# applies the filters.
Most efficient way to do it is to make the query as IQueryable with all the filters that you can apply.
And then build it up in memory and make the data formatting in C#.
IQueryable<Customer> dataQuery = Customers.Where(c => c.ID < 100 && c.ZIP == 12345 && c.Name == "John Doe");
var inMemCollection = dataQuery.AsEnumerable().Select(c => new
{
c.ID
c.Name,
c.ZIP,
c.DateRegisterred.ToString("dd,MMM,yyyy")
});
While SQL does not know what to do with a string.Format it can perform string concatenation.
If you run the following code then you should get the data you are after.
var taskList = from i in _db.Invoices
join a in _db.Areas on i.AreaId equals a.AreaId
where i.Status == InvoiceStatuses.Received && areaIds.Contains(a.AreaId)
select new Task {
LinkText = "Invoice " + i.InvoiceNumber + "has been received from " + i.Organisation.Name),
Link = Views.Edit
};
Once you actually perform the query this should be marginally faster than using AsEnumerable (at least that's what I found in my own code after having the same original error as you). If you are doing something more complex with C# then you will still need to use AsEnumerable though.

Read from CellSet using LINQ

AdomdCommand cmd = new AdomdCommand(commandText, conn);
CellSet cs = cmd.ExecuteCellSet();
var result = from a in cs
select new
{...};
Is it possible to use LINQ to read from CellSet? I have tried using DataTable instead of CellSet but it's much slower (Example: I took a query that using DataTable takes ~45 sec to execute, but using CellSet it takes ~5 sec).
The error I get when trying to use LINQ:
Could not find an implementation of the query pattern for source type
'Microsoft.AnalysisServices.AdomdClient.CellSet'. 'Select' not found.
UPDATE:
I have tried Enrico's suggestion and so far it doesn't return any errors. Next problem is how to read a value from a cell. Here's what I have tried so far:
var result = from cell in cs.Cells.Cast<Cell>()
select new searchResultsPolicy
{
PolicyNumber = ...
InsuredName = cell.Field<string>("[Insured].[DBA Name].[DBA Name].[MEMBER_CAPTION]"),
Agency = cell.Field<string>("[Agency].[Agency Name].[Agency Name].[MEMBER_CAPTION]"),
Market = cell.Field<string>("[Market].[Market Name].[Market Name].[MEMBER_CAPTION]"),
Revenue = String.Format("{0:#,##0}", cell.Field<double?>("[Measures].[Revenue]") ?? 0),
Premium = String.Format("{0:#,##0}", cell.Field<double?>("[Measures].[Premium]") ?? 0)
};
The reason you get that error is that the CellSet class in itself doesn't implement IEnumerable<T>, which is required by LINQ.
Try executing the LINQ query over the CellSet.Cells property instead. That will return a CellCollection object, which implements IEnumerable. From there you can easily convert it to an IEnumerable<T> by using the Enumerable.Cast<T> method.
AdomdCommand cmd = new AdomdCommand(commandText, conn);
CellSet cs = cmd.ExecuteCellSet();
var result = from cell in cs.Cells.Cast<Cell>()
select new
{ ... };
See also:
Retrieving Data Using the CellSet

Resources