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.
Related
I have two pieces of code which seems have same functionality but one of them lead to exception but another one is works like a charm. I want to know can you imagine why this happens?
I have below line in my web application which leads to this exception:
LINQ to Entities does not recognize the method 'System.Object
FilterDeliveryAddressFields(WebApplication1.Models.DeliveryAddress)'
dynamic deliveryAddresses = (from address in db.DeliveryAddress
select filterDeliveryAddressFields(address)).ToList();
And here is filterDeliveryAddressFields:
private dynamic filterDeliveryAddressFields(DeliveryAddress address)
{
return new { address.address, address.deliverTo, address.deliverToPhoneNumber, address.id };
}
And here is Linq-2-Sql generated Model for DeliveryAddress which have foreign key relationship with Subscriber:
public partial class DeliveryAddress
{
public int id { get; set; }
public int fkSubscriberId { get; set; }
public string address { get; set; }
public string deliverTo { get; set; }
public string deliverToPhoneNumber { get; set; }
public virtual Subscriber Subscriber { get; set; }
}
But when I change db.DeliveryAddress items to list first and then run code again as below everything goes well and no exception occurs again. I want to know what wrong with first code snippet which does not happen in below snippet?
List<DeliveryAddress> addresseList = db.DeliveryAddress.ToList(); //magic trick?!
dynamic deliveryAddresses =
(from address in addresseList
select filterDeliveryAddressFields(address)).ToList();
Actually, your method couldn't be translated to T-SQL, Linq to Entities couldn't recognize every method, the magic behind the .ToList() method which you are looking for is, after data is loaded, any further operation (such as select) is performed using LINQ to Objects, on the data already in memory.
However the performance is not guaranteed in this approach, as you have to load
your data into memory, so imagine you have a lot of data in your db, what will be happened next?
Agree with #Salah . In LINQ to Entities, it first try to convert your query to command tree and execute against your ORM. Please read here you can find more details.
In your first approach Linq tries to convert your filterDeliveryAddressFields(address)) method to command tree. That is why it complains that LINQ to Entities does not recognize the method.
In your second approach you execute against list or IEnumerable<T>, which means you use LINQ to Object. You can read more about it here.
For your first solution you can try another implementation. Simply try to use aggregate method to filter your result. Then you don't need filterDeliveryAddressFields(address)) method. You can find example here
Something like this, (Sorry I didn't try this my self. This is only for you to get an idea.)
from address in db.DeliveryAddress
select new { address.address, address.deliverTo, address.deliverToPhoneNumber, address.id };
I want to retrieve only one column of my data base. The following code works truly:
This is my customer in mysql-table/model-in-EF6
public partial class customers
{
public customers()
public int CustomerID { get; set; }
public string FullName { get; set; }
public string Mobile { get; set; }
public string Email { get; set; }
public string Address { get; set; }
public string Image { get; set; }
}
public List<customers> GetAllCustomers()
{
return myContext.customers.ToList();
}
This is my question:
var GetOneColumn = myContext.CustomerRepository.GetAllCustomers().Select(f=>f.FullName);
Does it retrieve all columns from customers in database and then select only one column (FullName) from retrieved data or not, it retrieve just only one column(FullName) from data base? If it retrieve all data from data base what is the correct code (Linq)?
How could I find that??
Since you're using a .ToList() EF will
Retrieve all customers from database
Map them to customer objects
Later, when you compute GetOneColumn, you do a projection on them (iterating through already materialized object list)
To retrieve only one column,
Remove the .ToList() from the repository, and return a IQueryable<Customers>
Call a .ToList() after your select var GetOneColumn = myContext.CustomerRepository.GetAllCustomers().Select(f=>f.FullName).ToList();
So, your code would be
public IQueryable<customers> GetAllCustomers()
{
return myContext.customers;
}
// later in code
var GetOneColumn = myContext.CustomerRepository.GetAllCustomers().Select(f=>f.FullName).ToList();
See what's going on for yourself! Break up your code into steps and debug:
var allCustomers = myContext.CustomerRepository.GetAllCustomers();
var allCustomerNames = allCustomers.Select(f=>f.FullName);
Alternatively, run a profiler on your DB, or enable logging of queries in EF
To see all the queries that EF is generating you can do something like this
using (var context = new BlogContext())
{
context.Database.Log = Console.Write;
// Your code here...
}
See more details in the docs and Log Queries executed by Entity Framework DbContext
If you read this far, then it's worth knowing what will actually cause EF to send a query - see How Queries Work
Basically, this happens whenever you start enumerating through the elements of an IQueryable<T> (including LINQ methods like First(), Last(), Single(), ToList(), ToArray(), and the like)
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
I want to pass a property list of a class to a function. with in the function based on property list I'm going to generate a query. As exactly same functionality in Linq Select method.
Here I'm gonna implement this for Ingress Database.
As an example,
in front end I wanna run a select as this,
My Entity Class is like this
public class Customer
{
[System.Data.Linq.Mapping.ColumnAttribute(Name="Id",IsPrimaryKey=true)]
public string Id { get; set; }
[System.Data.Linq.Mapping.ColumnAttribute(Name = "Name")]
public string Name { get; set; }
[System.Data.Linq.Mapping.ColumnAttribute(Name = "Address")]
public string Address { get; set; }
[System.Data.Linq.Mapping.ColumnAttribute(Name = "Email")]
public string Email { get; set; }
[System.Data.Linq.Mapping.ColumnAttribute(Name = "Mobile")]
public string Mobile { get; set; }
}
I wanna call a Select function like this,
var result = dataAccessService.Select<Customer>(C=>C.Name,C.Address);
then,using result I can get the Name and Address properties' values.
I think my Select function should looks like this,
( *I think this should done using Linq Expression. But im not sure what are the input parameter and return type. * )
Class DataAccessService
{
// I'm not sure about this return type and input types, generic types.
public TResult Select<TSource,TResult>(Expression<Func<TSource,TResult>> selector)
{
// Here I wanna Iterate through the property list, which is passed from the caller.
// Here using the property list,
// I can get the ColumnAttribute name value and I can generate a select query.
}
}
This is a attempt to create a functionality like in Linq. But im not an expert in Linq Expressions.
There is a project call DbLinq from MIT, but its a big project and still i couldn't grab anything helpful from that.
Can someone please help me to start this, or can someone link me some useful resources to read about this.
What you're trying to do is creating a new anonymous type that consists of Name and Address. This is easily achievable via long form linq (I made that term up, for lack of a better explanation.) Here's a sample from Microsoft, link provided below:
public void Linq11()
{
List<Product> products = GetProductList();
var productInfos =
from p in products
select new { p.ProductName, p.Category, Price = p.UnitPrice };
Console.WriteLine("Product Info:");
foreach (var productInfo in productInfos)
{
Console.WriteLine("{0} is in the category {1} and costs {2} per unit.", productInfo.ProductName, productInfo.Category, productInfo.Price);
}
}
Details: Linq Select Samples
Update:
So are you trying to do something like this then?
var result = dataAccessService.Select<Customer>(c => c.Name, c => c.Address);
public object[] Select<TSource>(params Expression<Func<TSource, object>>[] selectors)
{
var toReturn = new object[selectors.Count()];
foreach (var s in selectors)
{
var func = s.Compile();
//TODO: If you implement Select a proper extension method, you can easily get the source
toReturn[i] = func(TSource);
}
return toReturn;
}
I don't understand why you're trying to implement Select as a function of DataAccessService? Are trying to create this as an extension method rather?
If this is not what you mean though, you need to rephrase you're question big time and as one commenter suggested, tell us what you need not how you want us to design it.
I'm trying to grok Dapper and seem to be missing something very fundamental, can someone explain the following code taken from the Dapper home page on Google code and explain why there is no From clause, and the second param to the Query method (dynamic) is passed an anonymous type, I gather this is somehow setting up a command object, but would like an explanation in mere mortal terminology.
Thank you,
Stephen
public class Dog {
public int? Age { get; set; }
public Guid Id { get; set; }
public string Name { get; set; }
public float? Weight { get; set; }
public int IgnoredProperty {
get { return 1; }
}
}
var guid = Guid.NewGuid();
var dog = connection.Query<Dog>("select Age = #Age, Id = #Id", new { Age = (int?)null, Id = guid });
dog.Count().IsEqualTo(1);
dog.First().Age.IsNull();
dog.First().Id.IsEqualTo(guid);
The first two examples just don't do any "real" data access, probably in order to keep them simple.
Yes, there is a connection used (connection.Query(...)), but only because that's the only way to call Dapper's methods (because they extend the IDbConnection interface).
Something like this is perfectly valid SQL code:
select 'foo', 1
...it just does "generate" its result on the fly, without actually selecting anything from a table.
The example with the parameters and the anonymous type:
var dog = connection.Query<Dog>("select Age = #Age, Id = #Id", new { Age = (int?)null, Id = guid });)
...just shows Dapper's ability to submit SQL parameters in the form of an anonymous type.
Again, the query does not actually select anything from a table, probably in order to keep it simple.