I'm starting to write a wcf web service using the .NET 4.5 Entity Framework.
I'm having a hard time figuring out how to output the following linq query
here's my code:
using (var context = new myEntities())
{
var countResultsByArea = from v in context.vPerson
join pe in context.pEvent on v.pevent_id equals pe.pevent_id
join pd in context.pEventArea on pe.pevent_id equals pd.pevent_id
join d in context.dArea on pd.darea_id equals d.darea_id
join z in
(
from el in context.event
select new { el.event_id, el.title_1, el.title_2, el.event_date }
) on pe.event_id equals z.event_id
where (v.status.ToString() == "A" || v.status.ToString() == "P") && pe.event_id == 800
&& new[] { 435, 436, 437, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449 }.Contains(pd.area_id)
group new { d, z, v } by new { d.name_1, z.title_1 } into y
let myGroup = y.FirstOrDefault()
let myDArea = myGroup.d
let myPEvent = myGroup.z
select new { distArea = myDArea.name_1, title = y.Max(x => x.z.title_1), personCount = y.Count() };
if (countResultsByArea != null)
foreach (var item in countResultsByArea)
{
Console.WriteLine(item.distArea);
Console.WriteLine(item.title);
Console.WriteLine(item.personCount);
}
else
throw new Exception(string.Format("Error retrieving voter count by CD", "Error"));
}
I'm not getting errors until the foreach loop which returns an error of:
LINQ to Entities does not recognize the method 'System.String
ToString()' method, and this method cannot be translated into a store
expression.
I've seen other questions here with answers that uses .AsEnumerable to output the query as a List but I'm not sure how to modify the linq query since its so complex.
Any help would be greatly appreciated.
As the error clearly states, EF's query translator doesn't know what to do with ToString().
If that is a char, you can compare it to a character literal directly using single quotes.
Do not use the .ToString() on the v.status field.
where (v.status == "A" || v.status == "P") && pe.event_id == 800
Related
I've developed an apex API on salesforce which performs a SOQL on a list of CSV data. It has been working smoothly until yesterday, after making a few changes to code that follow the SOQL query, I started getting a strange 500 error:
[{"errorCode":"APEX_ERROR","message":"System.UnexpectedException:
common.exception.SfdcSqlException: ORA-01460: unimplemented or
unreasonable conversion requested\n\n\nselect /SampledPrequery/
sum(term0) \"cnt0\",\nsum(term1) \"cnt1\",\ncount(*)
\"totalcount\",\nsum(term0 * term1) \"combined\"\nfrom (select /*+
ordered use_nl(t_c1) /\n(case when (t_c1.deleted = '0') then 1 else 0
end) term0,\n(case when (upper(t_c1.val18) = ?) then 1 else 0 end)
term1\nfrom (select /+ index(sampleTab AKENTITY_SAMPLE)
*/\nentity_id\nfrom core.entity_sample sampleTab\nwhere organization_id = '00Dq0000000AMfz'\nand key_prefix = ?\nand rownum <=
?) sampleTab,\ncore.custom_entity_data t_c1\nwhere
t_c1.organization_id = '00Dq0000000AMfz'\nand t_c1.key_prefix = ?\nand
sampleTab.entity_id =
t_c1.custom_entity_data_id)\n\nClass.labFlows.queryContacts: line 13,
column 1\nClass.labFlows.fhaQuery: line 6, column
1\nClass.zAPI.doPost: line 10, column 1"}]
the zAPI.doPost() is simply our router class which takes in the post payload as well as the requested operation. It then calls whatever function the operation requests. In this case, the call is to labFlows.queryContacts():
Public static Map<string,List<string>> queryContacts(string[] stringArray){
//First get the id to get to the associative entity, Contact_Deals__c id
List<Contact_Deals__c> dealQuery = [SELECT id, Deal__r.id, Deal__r.FHA_Number__c, Deal__r.Name, Deal__r.Owner.Name
FROM Contact_Deals__c
Where Deal__r.FHA_Number__c in :stringArray];
//Using the id in the associative entity, grab the contact information
List<Contact_Deals__c> contactQuery = [Select Contact__r.Name, Contact__r.Id, Contact__r.Owner.Name, Contact__r.Owner.Id, Contact__r.Rule_Class__c, Contact__r.Primary_Borrower_Y_N__c
FROM contact_deals__c
WHERE Id in :dealQuery];
//Grab all deal id's
Map<string,List<string>> result = new Map<string,List<string>>();
for(Contact_Deals__c i:dealQuery){
List<string> temp = new list<string>();
temp.add(i.Deal__r.Id);
temp.add(i.Deal__r.Owner.Name);
temp.add(i.Deal__r.FHA_Number__c);
temp.add(i.Deal__r.Name);
for(Contact_Deals__c j:contactQuery){
if(j.id == i.id){
//This doesn't really help if there are multiple primary borrowers on a deal - but that should be a SF worflow rule IMO
if(j.Contact__r.Primary_Borrower_Y_N__c == 'Yes'){
temp.add(j.Contact__r.Owner.Id);
temp.add(j.Contact__r.Id);
temp.add(j.Contact__r.Name);
temp.add(j.Contact__r.Owner.Name);
temp.add(j.Contact__r.Rule_Class__c);
break;
}
}
}
result.put(i.Deal__r.id, temp);
}
return result;
}
The only thing I've changed is moving the temp list to add elements before the inner-loop (previously temp would only capture things from the inner-loop). The error above is referencing line 13, which is specifically the first SOQL call:
List<Contact_Deals__c> dealQuery = [SELECT id, Deal__r.id, Deal__r.FHA_Number__c, Deal__r.Name, Deal__r.Owner.Name
FROM Contact_Deals__c
Where Deal__r.FHA_Number__c in :stringArray];
I've tested this function in the apex anonymous window and it worked perfectly:
string a = '00035398,00035401';
string result = zAPI.doPost(a, 'fhaQuery');
system.debug(result);
Results:
13:36:54:947 USER_DEBUG
[5]|DEBUG|{"a09d000000HRvBAD":["a09d000000HRvBAD","Contacta","11111111","Plaza
Center
Apts"],"a09d000000HsVAD":["a09d000000HsVAD","Contactb","22222222","The
Garden"]}
So this is working. The next part is maybe looking at my python script that is calling the API,
def origQuery(file_name, operation):
csv_text = ""
with open(file_name) as csvfile:
reader = csv.reader(csvfile, dialect='excel')
for row in reader:
csv_text += row[0]+','
csv_text = csv_text[:-1]
data = json.dumps({
'data' : csv_text,
'operation' : operation
})
results = requests.post(url, headers=headers, data=data)
print results.text
origQuery('myfile.csv', 'fhaQuery')
I've tried looking up this ORA-01460 apex error, but I can't find anything that will help me fix this issue.
Can any one shed ore light on what this error is telling me?
Thank you all so much!
It turns out the error was in the PY script. For some reason the following code isn't functioning as it is supposed to:
with open(file_name) as csvfile:
reader = csv.reader(csvfile, dialect='excel')
for row in reader:
csv_text += row[0]+','
csv_text = csv_text[:-1]
This was returning one very long string that had zero delimiters. The final line in the code was cutting off the delimiter. What I needed instead was:
with open(file_name) as csvfile:
reader = csv.reader(csvfile, dialect='excel')
for row in reader:
csv_text += row[0]+','
csv_text = csv_text[:-1]
Which would cut off the final ','
The error was occurring because the single long string was above 4,000 characters.
Scratching head here. I've got a pulldown and if I query it in SQL Server Manager Query Window I get 5 different values (these are sample points for a water system).
However, when the pulldown loads, there are 5 options of the first value. Can someone see something I can't?
I narrowed it down to the code below because I held my cursor over "results" which was the final step in my Controller's code, and it showed 5 items all of the same value:
else if ((sampletype == "P") || (sampletype == "T") || (sampletype == "C") || (sampletype == "A"))
{
var SamplePoints = (from c in _db.tblPWS_WSF_SPID_ISN_Lookup
where c.PWS == id && c.WSFStateCode.Substring(0, 1) == "S"
select c).ToList();
if (SamplePoints.Any())
{
var listItemsBig = SamplePoints.Select(p => new SelectListItem
{
Selected = false,
Text = p.WSFStateCode.ToString() + ":::" + p.SamplePointID.ToString(),
Value = p.WSFStateCode.ToString()
}).ToList();
results = new JsonResult { Data = listItemsBig };
}
}
return results ;
}
I have had a similar problem in nHibernate, it was caused by how I defined my primary keys/foreign keys in the ORM, leading to a bad join and duplicate values.
How can I select data with such linq to sql code, it's something wrong, i must compare WHERE, from st1 and st2, but something wrong. Also spaller didn't light this variables in where
var st1 = (from a in db.RouteDetail
where a.Station == "Гродно"
select new
{
a.Route,
});
var st2 = (from c in db.RouteDetail
where c.Station == "Лида"
select new
{
c.Route,
});
var res = (from d in db.RouteDetail
where st1.Route == st2.Route
select d);
Help me to do this, please.
I think what you mean to do is something like this :
var st1 = (from a in db.RouteDetail
where a.Station == "Гродно"
select new
{
a.Route,
});
var st2 = (from c in db.RouteDetail
where c.Station == "Лида"
select new
{
c.Route,
});
Both st1 and st2 now contain IQueryable types which allow you to enumerate over them. I'm assuming that your two queries only return one result in which case:
var station1 = st1.FirstorDefault();
var station2 = st2.FirstorDefault();
var res = (from d in db.RouteDetail
where station1.Route == station2.Route
select d);
Will do what you need it to do (provided they return a result theres no safety here for null exceptions). If however there is more than one result, it will only return the first match. In which case you will need to work out all the possible compositions from the values in st1 and st2
I'm trying to get a paged query to work properly using LINQ and NHibernate. On a single table, this works perfect, but when more than one table is joined, it's causing me havoc. Here is what I have so far.
public virtual PagedList<Provider> GetPagedProviders(int startIndex, int count, System.Linq.Expressions.Expression<Func<Record, bool>> predicate) {
var firstResult = startIndex == 1 ? 0 : (startIndex - 1) * count;
var query = (from p in session.Query<Record>()
.Where(predicate)
select p.Provider);
var rowCount = query.Select(x => x.Id).Distinct().Count();
var pageOfItems = query.Distinct().Skip(firstResult).Take(count).ToList<Provider>();
return new PagedList<Provider>(pageOfItems, startIndex, count, rowCount);
}
There are a couple issues I'm having with this. First off, the rowCount variable is pulling back a COUNT(*) on a join that has one to many. So my count is way off of what is should be, I'm expecting 129, but getting back over 1K.
The second issue I'm happening is with the results. If I'm on the first page (firstResult = 0), then I'm getting correct results. However, if firstResult is something other than 0, it produces completely different SQL. Below is the SQL generated by both scenarios, I've trimmed out some of the fat to make it a little more readable.
--firstResult = 0
select distinct TOP (30) provider1_.Id as Id12_, provider1_.TaxID as TaxID12_,
provider1_.Facility_Name as Facility5_12_, provider1_.Last_name as Last6_12_,
provider1_.First_name as First7_12_, provider1_.MI as MI12_
from PPORecords record0_ left outer join PPOProviders provider1_ on record0_.Provider_id=provider1_.Id,
PPOProviders provider2_ where record0_.Provider_id=provider2_.Id
and provider2_.TaxID='000000000'
--firstResult = 30
SELECT TOP (30) Id12_, TaxID12_, Facility5_12_, Last6_12_, First7_12_, MI12_,
FROM (select distinct provider1_.Id as Id12_, provider1_.TaxID as TaxID12_,
provider1_.Facility_Name as Facility5_12_,
provider1_.Last_name as Last6_12_,
provider1_.First_name as First7_12_,
provider1_.MI as MI12_,
ROW_NUMBER() OVER(ORDER BY CURRENT_TIMESTAMP) as __hibernate_sort_row
from PPORecords record0_ left outer join PPOProviders provider1_ on record0_.Provider_id=provider1_.Id,
PPOProviders provider2_
where record0_.Provider_id=provider2_.Id and provider2_.TaxID='000000000') as query
WHERE query.__hibernate_sort_row > 30
ORDER BY query.__hibernate_sort_row
The problem with the second query is the "distinct" keyword is not present on the outer query, only the inner query. Any ideas how to correct this?
Thanks for any suggestions!
[UPDATE]
This is the code that is building the the Linq query predicate.
private Expression<Func<Record, bool>> ParseQueryExpression(string Query) {
Expression<Func<Record, bool>> mExpression = x => true;
string[] splitQuery = Query.Split('|');
foreach (string query in splitQuery) {
if (string.IsNullOrEmpty(query))
continue;
int valStartIndex = query.IndexOf('(');
string variable = query.Substring(0, valStartIndex);
string value = query.Substring(valStartIndex + 1, query.IndexOf(')') - valStartIndex - 1);
switch (variable) {
case "tax":
mExpression = x => x.Provider.TaxID == value;
break;
case "net":
mExpression = Combine<Record>(mExpression, x => x.Network.Id == int.Parse(value));
break;
case "con":
mExpression = Combine<Record>(mExpression, x => x.Contract.Id == int.Parse(value));
break;
case "eff":
mExpression = Combine<Record>(mExpression, x => x.Effective_Date >= DateTime.Parse(value));
break;
case "trm":
mExpression = Combine<Record>(mExpression, x => x.Term_Date <= DateTime.Parse(value));
break;
case "pid":
mExpression = Combine<Record>(mExpression, x => x.Provider.Id == long.Parse(value));
break;
case "rid":
mExpression = Combine<Record>(mExpression, x => x.Rate.Id == int.Parse(value));
break;
}
}
return mExpression;
}
It seems as if the Linq provider has some "unexpected" behaviour there. I could reproduce the issue with the rowCount that you are describing and also encountered some issues when trying to fix it with a subquery.
If I understand your intentions correctly you basically want to have a paged list of Providers whose Records match certain criteria.
In that case I would suggest using a subquery. However, I tried implementing the subquery with the Query() method but it did not work. So I tried the QueryOver() method which worked flawlessly. In your case the desired queries would look like this:
Provider pAlias = null;
var query = session.QueryOver<Provider>(() => pAlias).WithSubquery
.WhereExists(QueryOver.Of<Record>()
.Where(predicate)
.And(r => r.Provider.Id == pAlias.Id)
.Select(r => r.Provider));
var rowCount = query.RowCount();
var pageOfItems = query.Skip(firstResult).Take(count).List<Provider>();
That way you do not have to struggle with the Distinct(). And as much as I personally like and use NHibernate.Linq, I suppose, if it does not work in a given situation, one should use something else that works.
Edit: Splitting the query into smaller units.
// the method ParseQueryExpression() does not need to be modified, the Expression should work like that
System.Linq.Expressions.Expression<Func<Record, bool>> predicate = x => x.Provider.TaxID == "000000000";
// Query to evaluate predicate
IQueryable<Record> queryId = session.Query<Record>().Where(predicate).Select(r => r.Provider);
// extracting the IDs to use in a subquery
List<int> idList = queryId.Select(p => p.Id).Distinct().ToList();
// total count of distinct Providers
int rowCount = idList.Count;
// new Query on Provider, using the distinct Ids
var query = session.Query<Provider>().Where(p => idList.Contains(p.Id));
// the List<Provider> to display on the page
var pageOfItems = query.Skip(firstResult).Take(count).ToList();
The problem here is that you have multiple queries and therefore multiple roundtrips to the db. Another problem apperas when you examine the generated sql. The subquery idList.Contains(p.Id) will generate an in-clause with a lot of parameters.
As you can see, these are NHibernate.Linq queries. That is because the new QueryOver feature is not a true Linq provider and does not work well with dynamic Linq expressions.
You could get around that limitation by using Detached QueryOvers. The drawback here is that you would have to modify your ParseQueryExpression() somehow, e.g. like that:
private QueryOver<Record> ParseQueryExpression(string Query)
{
Record rAlias = null;
var detachedQueryOver = QueryOver.Of<Record>(() => rAlias)
.JoinQueryOver(r => r.Provider)
.Where(() => rAlias.Provider.TaxID == "000000000")
.Select(x => x.Id);
// modify your method to match the return value
return detachedQueryOver;
}
// in your main method
var detachedQueryOver = QueryOver.Of<Record>()
.WithSubquery
.WhereProperty(r => r.Id
.In(this.ParseQueryExpression(...));
var queryOverList = session.QueryOver<Provider>()
.WithSubquery
.WhereProperty(x => x.Id)
.In(detachedQueryOver.Select(r => r.Provider.Id));
int rowCount = queryOverList.RowCount();
var pageOfItems = queryOverList.Skip(firstResult).Take(count).List();
Well, I hope you are not too confused by that.
Is there a lambda equivalent of IN? I will like to select all the funds with ids either 4, 5 or 6. One way of writing it is:
List fundHistoricalPrices = lionContext.FundHistoricalPrices.Where(fhp => fhp.Fund.FundId == 5 || fhp.Fund.FundId == 6 || fhp.Fund.FundId == 7).ToList();
However, that quickly becomes unmanageable if I need it to match say 100 different fundIds. Can I do something like:
List
fundHistoricalPrices =
lionContext.FundHistoricalPrices.Where(fhp
=> fhp.Fund.FundId in(5,6,7)).ToList();
It's somewhere along these lines, but I can't quite agree with the approach you have taken. But this will do if you really want to do this:
.Where(fhp => new List<int>{5,6,7}.Contains( fhp.Fund.FundId )).ToList();
You may want to construct the List of ids before your LINQ query...
You can use the Contains() method on a collection to get the equivalent to in.
var fundIds = new [] { 5, 6, 7 };
var fundHistoricalPrices = lionContext.FundHistoricalPrices.Where(fhp => fundIds.Contains(fhp.Fund.FundId)).ToList();
You could write an extension method like this :
public static bool In<T>(this T source, params T[] list)
{
if(null==source) throw new ArgumentNullException("source");
return list.Contains(source);
}
Then :
List fundHistoricalPrices = lionContext.FundHistoricalPrices.Where(fhp => fhp.Fund.FundId.In(5,6,7)).ToList();
No, the only similar operator i'm aware of is the Contains() function.
ANother was is to construct your query dynamically by using the predicate builder out of the LINQkit: http://www.albahari.com/nutshell/predicatebuilder.aspx
Example
int[] fundIds = new int[] { 5,6,7};
var predicate = PredicateBuilder.False<FundHistoricalPrice>();
foreach (int id in fundIds)
{
int tmp = id;
predicate = predicate.Or (fhp => fhp.Fund.FundId == tmp);
}
var query = lionContext.FundHistoricalPrices.Where (predicate);