Cast works fine, but Convert not [duplicate] - c#

I'm new to Entity Framework. I'm trying to retrieve data from the database using a LINQ query and Entity Framework.
IEnumerable<Gate> lstGate = from tbsite in dc.tblSites
select new Gate
{
CalledInAt = DateTime.Parse(tbsite.CalledInAt.ToString(), new CultureInfo("en-GB", false)),
RemoteType = tbsite.RemoteType,
NoOfRemotes = (tbsite.NoOfRemotes == null) ? 0 : Convert.ToInt32(tbsite.NoOfRemotes),
GateType = tbsite.GateType,
NoOfRacks = (tbsite.NoOfRacks == null) ? 0 : Convert.ToInt32(tbsite.NoOfRacks),
};
My Model:
public class Gate
{
public DateTime CalledInAt { get; set; }
public string RemoteType { get; set; }
public int NoOfRemotes { get; set; }
public string GateType { get; set; }
public int NoOfRacks { get; set; }
public string ClickToEdit { get; set; }
}
I'm getting following errors.
"LINQ to Entities does not recognize the method 'System.DateTime
Parse(System.String, System.IFormatProvider)' method, and this method
cannot be translated into a store expression."} System.SystemException
{System.NotSupportedException}
{"LINQ to Entities does not recognize the method 'Int32
ToInt32(System.Object)' method, and this method cannot be translated
into a store expression."} System.SystemException
{System.NotSupportedException}

As Nilesh already pointed out in his comment
You cannot use .Net function inside LINQ, because this will be converted into an actual SQL. That is the reason it is complaining about the conversion. Example = you cannot use Convert.toInt32 as the SQL Server does not know what this function is.
An easy fix for your problem would be to call ToList(). This will execute the query and populate a list with the results. After that it is possible to use ToString() or Convert.ToInt32 cause the values are all in-memory and you are free to use .NET methods.
IEnumerable<Gate> lstGate = from tbsite in dc.tblSites.ToList()
select new Gate
{
CalledInAt = DateTime.Parse(tbsite.CalledInAt.ToString(), new CultureInfo("en-GB", false)),
RemoteType = tbsite.RemoteType,
NoOfRemotes = (tbsite.NoOfRemotes == null) ? 0 : Convert.ToInt32(tbsite.NoOfRemotes),
GateType = tbsite.GateType,
NoOfRacks = (tbsite.NoOfRacks == null) ? 0 : Convert.ToInt32(tbsite.NoOfRacks),
};
The call dc.tblSites.ToList() will read all values and rows from the table. If you want to apply sorting or filtering to reduce the amount of read data, then you need to apply the Where() or OrderBy() calls before ToList()

you are getting that error because the Select part is being sent to the server by EF
two things
1) the objects from dc.tblSites can be directly used.
2) if you really want to transform them first get the data from the database then create the object
.ToArray() is a good one.
... from tbsite in dc.tblSites.ToArray() ...

Related

Need to convert Left join SQL to linq query - help appreciated

Here is my code the issue I have is the less than comparison in the On clause ... Since Linq doesn't allow this .... Migrating down into the where clause wont work as I am comparing one of the fields to null.
Here is the sql query (THE a.UserID= is hardcoded for now)
SELECT A.Policy, A.Comments, A.EventDTTM, A.Status, A.Reason, A.FollowUp
FROM PP_PolicyActivity A
LEFT JOIN PP_PolicyActivity B
ON(A.Policy = B.Policy AND A.EventDTTM < B.EventDTTM)
WHERE A.UserID = 'Ixxxxxx'
AND B.EventDTTM IS NULL AND a.status = 'open - Pending'
order by A.EventDTTM DESC
I need the result set from the above query as an IEnumerable list to populate a view
I'm tasked with rebuilding an old VB ASP NET that has a set of standing production databases behind it ... i don't have the option of changing the db design. I connecting to the server and database and this query was going against a table on that database.. the model also reflects the layout of the actual table.
The problem is with A.EventDTTM < B.EventDTTM - I can't move this to the where clause as I also have to deal with B.EventDTTM IS NULL in the where clause.
I need to retool the query someway so that it is 'linq' friendly
public class PolicyActivityModel
{
public string Policy { get; set; }
public int PolicyID { get; set; }
public string Status { get; set; }
public string Reason { get; set; }
public string Comments { get; set; }
public DateTime EventDTTM { get; set; }
public string UserID { get; set; }
public DateTime FollowUp { get; set; }
}
Company policy prohibits me from showing the connection string.
I am extremely new to Linq, Any help greatly appreciated
thank you
You can use the navigation property after you get the policy from the database.
var policy = DbContext.First(x => x.Id == 1000);
var otherPolicies = policy.ConnectedPolicies.Where(p => ...);
It's weird being a self-join but this is the most direct translation to Linq:
var query = from leftPP in PP_PolicyActivity
join rightPP in PP_PolicyActivity
on new { Policy = leftPP.Policy, EventDTTM = leftPP.EventDTTM }
equals new { Policy = rightPP.Policy, EventDTTM = rightPP.EventDTTM }
into pp from joinedRecords.DefaultIfEmpty()
where leftPP.UserId == 1
&& leftPP.EventDTTM < rightPP.DTTM)
&& rightPP.EventDTTM == null
&& leftPP.status = "open - Pending"
select new
{
leftPP,
rightPP
}
I free typed this, without models or Intellisense, thus there might be some smaller errors.
You could add the order by in that clause, but it's also still an IQUeryable, so I'd leave it.
And then, to get a List of models:
var results = query.OrderByDescending(x => x.EventDTTM).ToList();
The actual join is lines 2,3,4 and 5. It's verbose and "backwards" from SQL, and most importantly uses anonymous types. Accessing indidual properties will look something like:
results[0].leftPP.PolicyId

How to create dynamic Linq Select Expression with anonymous objects

Am using Entity Framework to run a query on a table. However, i need to get select columns only.
class MyEvent
{
public string Name { get; set; }
public int Id { get; set; }
virtual Stage EventStage { get; set; }
..... more columns .....
}
class Stage
{
public string Name { get; set; }
public string Location { get; set; }
..... more columns .....
}
I can write an IQueryable to return these as
dbContext.MyEvents
.Select(s =>
new {
Name = s.Name,
Id = s.Id,
EventStage = new
{
Name = s.EventStage.Name,
Id = s.EventStage.Id
}
}
)
.ToList();
This works as expected, giving me just those columns am interested in.
Now, I need to construct that 'Select' call dynamically using Expression tree, something like here.
How can I achieve that? Is it feasible to construct an anynomous object, like above, via expressions?
EDIT:
The use case for me is that I have a generic dB context class which takes a list of columns as strings to be fetched. In the past, we were returning all columns, ignoring that input list. So, now I need to dynamically generate the select statement to return only the required subset of columns, which can either be done via anonymous object or a dynamically created DTO.
Thanks
Maybe you can use something like the ToDynamic method from here:
https://gist.github.com/volak/20f453de023ff75edeb8
A possible usecase for this problem:
Let the user select the columns to display and query only those selected columns, so you don't query always the whole entity from the database.
Define a strongly typed object and return that. I would avoid using a dynamic object.
Note: you can't return an anonymous object.

Returning IQueryable type: The entity or complex type '' cannot be constructed in a LINQ to Entities query

I am running a query to populate options in a single select drop down menu. When I debug the function below, the query variable contains the resultset that I am expecting. However when I skip next to where it should be returned to, I get the error:
'The entity type or complex type 'Models.zz_Member' cannot be constructed in a LINQ to Entities query."
public IQueryable<zz_Member> GetMembers(string searchText)
{
var _db = new Portal.Models.AuthorizationContext();
IQueryable<zz_Member> query = _db.zz_Members;
return query //.Where(a => a.memLastName.Contains(searchText))
.Select(a => new zz_Member()
{
ID = a.ID,
memFirstName = a.memFirstName,
memLastName = a.memLastName
}
);
}
The zz_Member model object is defined as:
public class zz_Member
{
[ScaffoldColumn(false)]
public int ID { get; set; }
public string memFirstName { get; set; }
public string memLastName { get; set; }
}
The error is thrown when I try to convert to an IList, but when I check the value of memList using the debugger, it shows the error text in the results view.
IQueryable<zz_Member> memList = GetMembers(e.Text);
IList<zz_Member> memList2 = memList.ToList();
I have also tried writing the GetMembers functions to return the list as so:
public IList<zz_Member> GetMembers(string searchText)
{
var _db = new WWCPortal.Models.AuthorizationContext();
return (from m in _db.zz_Members
where m.memLastName.Contains(searchText)
select new zz_Member { ID = m.ID, memFirstName = m.memFirstName, memLastName = m.memLastName }).ToList();
}
Any hints or answers to why the resultset appears to not be getting returned to the caller and put into memList? Thanks.
You cannot use framework dependant/generated entities in projection (with select new), hence the error.
Looks like you are trying to select specific columns instead of all columns, your options are
Project to a new class with those specific members
return all fields/columns for your entities like:
Code:
return query.Where(a => a.memLastName.Contains(searchText)); //without `select new`

Lambda expression with .Where clause using Contains

When connecting to CRM 2013 is there a smart way to create a lambda expression that gets the entities who's GUID are in a List.
This code breaks on the Where clause and gives the error:
Invalid 'where' condition. An entity member is invoking an invalid property or method.
Code:
private List<UserInformationProxy> GetContactsFromGuidList(List<Guid> contactList)
{
var result = _serviceContext.ContactSet
.Where(x=> contactList.Contains((Guid) x.ContactId)) // this line breaks
.Select(x => new UserInformationProxy()
{
FullName = x.FullName,
Id = x.ContactId
})
.Distinct()
.ToList<UserInformationProxy>();
return result;
}
// return class
public class UserInformationProxy
{
public Guid? Id { get; set; }
public string FullName { get; set; }
public string DomainName { get; set; }
}
Currently I'm solving this by getting all the contacts from the ContactSet and sorting out the ones I want with a loop in my code. This works, but is quite slow as I need to get all 10000 contacts instead of sending the Guids of the 40 Im actually interested in to the SQL server.
QueryExpressions support an In operator, so this should work just fine:
private List<UserInformationProxy> GetContactsFromGuidList(List<Guid> contactList)
{
var qe = new QueryExpression(Contact.EntityLogicalName);
qe.ColumnSet = new ColumnSet("fullname", "contactid")
qe.Criteria.AddCondition("contactid", ConditionOperator.In, list.Cast<Object>().ToArray());
qe.Distinct = true;
var results = service.RetrieveMultiple(qe).Entities.Select (e => e.ToEntity<Contact>()).
Select(x => new UserInformationProxy()
{
FullName = x.FullName,
Id = x.ContactId
});
return results;
}
On a side note, every Contact has to have an Id that is not empty, so there is no need to check for it.
EDIT: It is possible to accomplish using a single query, Daryl posted an answer with the right code.
Other (not so clever) alternatives are:
Retrieve all the records and after check the Guids
Do a single retrieve for each Guid
Because are only 40 records, I suggest to use late-bound to retrieve the records, in order to choose the minimal ColumnSet.
Useful links related to this issue:
Another question regarding Dynamics CRM LINQ limitations
Performance test Early Bound vs Late Bound

IQueryable returns null on invoking Count c#

I have a problem trying to get the count out of the following query:
var usersView = PopulateUsersView(); //usersView is an IQueryable object
var foo = usersView.Where(fields => fields.ConferenceRole.ToLower().Contains("role"));
Where UsersView is a class which is populated from an EF entity called users (refer to the first line in the code above)
This is the class definition for the UsersView class:
public class UsersView
{
public int UserId { get; set; }
public string Title { get; set; }
public string Name { get; set; }
public string Surname { get; set; }
public string Street1 { get; set; }
public string Street2 { get; set; }
public string City { get; set; }
public string PostCode { get; set; }
public string CountryName { get; set; }
public string WorkPlaceName { get; set; }
public string Gender { get; set; }
public string EMail { get; set; }
public string Company { get; set; }
public string RoleName { get; set; }
public string ConferenceRole { get; set; }
}
As I said trying to execute the line foo.Count() returns Null Exception and this might be because the ConferenceRole column allows Null in the database.
Now what I can't understand is that when I invoke the same query directly on the ObjectQuery the Count of records (i.e. invoking foo2.Count()) is returned without any exceptions.
var foo2 = entities.users.Where(fields => fields.ConferenceRole.ToLower().Contains("role"));
Is it possible to the same query above but using the IQueryable usersView object instead?
(It is crucial for me to use the usersView object rather than directly querying the entities.users entity)
EDIT
Below is the code from the PopulateUsersView method
private IQueryable<UsersView> PopulateUsersView()
{
using (EBCPRegEntities entities = new EBCPRegEntities())
{
var users = entities.users.ToList();
List<UsersView> userViews = new List<UsersView>();
foreach (user u in users)
{
userViews.Add(new UsersView()
{
UserId = u.UserId,
Title = u.Title,
Name = u.Name,
Surname = u.Surname,
Street1 = u.Street1,
Street2 = u.Street2,
City = u.City,
PostCode = u.Post_Code,
CountryName = u.country.Name,
WorkPlaceName = u.workplace.Name,
Gender = u.Gender,
EMail = u.E_Mail,
Company = u.Company,
RoleName = u.roles.FirstOrDefault().Name,
ConferenceRole = u.ConferenceRole
});
}
return userViews.AsQueryable();
}
}
Thanks
UPDATE...
Thanks guys I finally found a good answer to the difference between the IQueryable and the ObjectQuery objects.
As a solution I am checking if the ConferenceRole is null and then checking with the contains method as many of you guys have said.
My guess is that your PopulateUsersView() method is actually executing a query and returning an IQueryable Linq-to-Objects object - while the foo2 line executes the query only in the SQL layer. If this is the case, the obviously PopulateUsersView() is going to be quite an inefficient way to perform the Count
To debug this:
can you post some code from PopulateUsersView()?
can you try running both sets of code through the EF tracing provider to see what is executed in SQL? (see http://code.msdn.microsoft.com/EFProviderWrappers)
Update
#Ryan - thanks for posting the code to PopulateUsersView
Looks like my guess was right - you are doing a query which gets the whole table back into a List - and its this list that you then query further using Linq2Objects.
#ntziolis has provided one solution to your problem - by testing for null before doing the ToLower(). However, if your only requirement is to Count the non-empty items list, then I recommend you look at changing the PopulateUsersView method or changing your overall design. If all you need is a Count then it would be much more efficient to ensure that the database does this work and not the C# code. This is espeically the case if the table has lots of rows - e.g. you definitely don't want to be pulling 1000s of rows back into memory from the database.
Update 2
Please do consider optimising this and not just doing a simple != null fix.
Looking at your code, there are several lines which will cause multiple sql calls:
CountryName = u.country.Name
WorkPlaceName = u.workplace.Name
RoleName = u.roles.FirstOrDefault().Name
Since these are called in a foreach loop, then to calculate a count of ~500 users, then you will probably make somewhere around 1501 SQL calls (although some roles and countries will hopefully be cached), returning perhaps a megabyte of data in total? All this just to calculate a single integer Count?
Try to check whether ConferenceRole is null before calling a method on it:
var foo = usersView.Where(fields => fields.ConferenceRole != null
&& fields.ConferenceRole.ToLower().Contains("role"));
This will enable you to call the count method on the user view.
So why does it work against the ObjectQuery?
When executing the query against the ObjectQuery, LinqToSql is converting your query into proper sql which does not have problems with null values, something like this (it's sample markup sql only the actual query looks much different, also '=' is used rather than checking for contains):
SELECT COUNT(*) from USERS U WHERE TOLOWER(U.CONFERENCEROLE) = 'role'
The difference to the :NET code is: It will not call a method on an object but merely call a method and pass in the value, therefore no NullReference can occur in this case.
In order to confirm this you can try to force the .NET runtime to execute the SQL prior to calling the where method, by simply adding a ToList() before the .Where()
var foo2 = entities.users.ToList()
.Where(fields => fields.ConferenceRole.ToLower().Contains("role"));
This should result in the exact same error you have seen with the UserView.
And yes this will return the entire user table first, so don't use it in live code ;)
UPDATE
I had to update the answer since I c&p the wrong query in the beginning, the above points still stand though.

Categories

Resources