How does entity framework optimize linq queries - linq

I am using Azure Mobile Web Services with an Entity Framework Database and am wondering about how to structure my linq query. I have a UserSetting and a User table, with UserSetting being a one-to-many with User. However, since I don't have referential constraints, I don't have a UserId property to query against in linq. So, I'd like to, in one operation, get the UserId and get all UserSettings belonging to the user. Also, I'm posting here because I'm having a hard time figuring out break points on a Web Service when a query is run so I can look at the SQL
So, my question is are these two queries the same thing?
return Query().Where(setting => setting.User.AccountId == currentUser.Id);
return from setting in Query()
let user = context.Users.SingleOrDefault(user => user.AccountId == currentUser.Id)
where setting.User == user
select setting;

Related

Linq to Crm (2011) Trouble searching by username for systemuser

I have a win app that is using linq to crm to query a system user by username
in Crm 2011(IFD). I have the following code snippet which shows what I am trying
to accomplish. The method executes without error, however no records are found.
The username appears as "domain\testuser" om CRM.
public static SystemUser LookUpSystemUser()
{
var username= "domain\\testuser");
var list = (from c in Context.CreateQuery<SystemUser>()
where c.DomainName.Equals(username)
select c).ToList();
return list.FirstOrDefault();
}
Recreating the application seemed to fix the problem. There are still no code differences, so still unsure what happened.
This really isn't an answer to your question, and in your particular instance it really won't matter due to there only being one SystemUser per DomainName, but it is a best practice.
When calling ToList() on your LINQ statement, it will return all entities from the SQL database that match the query. Then calling FirstOrDefault() will return the first, client side.
Instead of calling ToList() when only interested in one, call FirstOrDefault(). This will actually result in Top 1 added to the select query. This will result in less resources being consumed on the SQL server, CRM Webserver, and data being transfered between the SQL server, the CRM Webserver, and the client.
Try to run this method (or a canonical equivalent of it) and see if you get anything at all. If so, you can then tighten up the condition in Select statement.
public static SystemUser LookUpSystemUser()
{
return Context.CreateQuery<SystemUser>()
.Select(element => true)
.FirstOrDefault();
}
Remember that default(SystemUser) will produce null.
Not at the computer, haven't tested it.

Is it possible to map Linq queries from one Data Model to a query over a different data model?

I would like to provide an OData interface for my application. The examples that I have seen use EF to map the LINQ queries to SQL queries.
IMHO it this approach pretty much exposes the physical database model to the world (I know EF/NH give some flexibility, but it is limited).
What I would like the be able to do, is the following:
Define my Data Contract via some DTOs.
Have a OData Service that will let users query over my Data Contract Dtos.
Have some translation layer to translate the queries over the DTOs to queries over, let's say, EF model or NH.
Execute the translated query.
Map the results back to my Data Contracts.
Am I out of my mind or is there a solution to this problem?
I have 2 models, the "contract" model and the "persisted" model. The persisted model is what Entity Framework is mapped to. The Get method that returns an IQueryable returns a IQueryable which is just something along the lines of:
return dbContext.PersistedCustomers.Select(x => new Customer(Name = x.OtherName, ...));
At least when using DbContext as opposed to ObjectContext, Where criteria based on the contract model get translated automatically into Where criteria of the PersistedModel to be executed against the database. Hopefully the differences between the two aren't that complex that you need some weird data massaging. I'm sure there's limits to the reversal it does.
One way of doing it would be to create a ViewModel that will represent your Model and then use AutoMapper to map between them. You can use like this:
var address = _Context.Addresses.Where(p => p.AddressID == addressID).Single();
AddressVM result = Mapper.Map<AddressVM>(address);

Linq doubts with DB context

Hi I have a question that is braking my mind for some days.
I have my SQL server Database and my C# application.
In the DB I have differemt tables, let me show you a simple ex
Tables:
Person
Relationship
City
Business Rules:
The person are from a City, so the person has IdCity
A person has a relationship with other person, and about that relationship you need to save the starting date.
In other projects I already did something like that, but in this proyect this is not working for me.
When I retrieved with LinQ the information about the person, the city is not coming, and an error appears when I try "person.city.description", for ex.
I try using Include("City") in the linq query, but it didn't work. Besides that, I don't know how to manage the circular reference to the person to person relationship.
One important thing, that I think that can be the problem, is that I rename all the tables from the DataModel, for example, the table in database is called Prd_City, so I change the Name and the Entity Set Name for City in c# project. So in the included I have to use the real table name, in other case the query fail, but if I use the real name nothing happens.
using (var context = new MyContext())
{
List<Person> oPeople = (from p in context.Person.Include("Prd_City")
select p).ToList();
return oPeople ;
}
Any help will be welcome.
Thanks!
"It didn't work" is never a good description of your problem. But from the rest of your question I can infer that Person has a navigation property named "Prd_City", while you expected it to be "City". The thing is: you renamed the entities, but not the navigation properties in the entities.
My advice (for what it's worth): it seems that your work database-first. If you can, change to code-first and manually map the POCO classes to their table names, and properties to their database columns. It may be a considerable amount of work (depending on the size of your data model), but after that you will never run the risk of EF "un-renaming" your entities. Besides, the DbContext API is easier to use than ObjectContext. Currently, it's the preferred EF API.

How to connect a users table correctly to a Membership table, or should you even do that?

I'm probably going about this the wrong way, please feel free to correct me.
Currently I have a User model called U_USER, it contains fields such as address, receiveNotifications, HasCompanyCar Etc.
These users have roles in a .NET Membership table. When the user logs in via Membership, I get their user record in my database as follows (the username on the Membership table and my own U_USER table will have a match):
//Gets the current user
public U_USER CurrentUser()
{
return GetUser(HttpContext.Current.User.Identity.Name);
}
//Gets user details by username
public U_USER GetUser(String username)
{
return (from u in db.U_USER
where u.UserName == username
select u).FirstOrDefault();
}
If I wanted to get a list of all users in, lets say, the "Create" role then I would do this:
allUsers.Where(x => Roles.IsUserInRole(x.UserName, "Create"))
This is a big performance hit as it's doing a lookup for each iteration of a user. This makes me think I'm not going about user management in the correct way. So to answer this question:
How should you properly connect Membership to a users table that in turn is connected to the rest of your data? I'd also accept how to just go about it more efficiently!
Many thanks :)
EDIT :
I've increased performance via the below code. I get the users in the role in one swoop and then filter them.
String[] usersInRole = Roles.GetUsersInRole("CanApprove");
users = users.Where(x => usersInRole.Any(y => y == x.UserName));
But I'm still fairly sure I'm going about this ALL wrong!
Not an expert in this, but what my apps typically do is to use a foreign key (with Index) from my own Users table to the Membership Users table using the Guid field with the Membership. This then allows me to do queries using Linq like:
var query = from myUser in MyUsers
join aspUser in aspnet_Users on myUser.UserId equals aspUser.UserId
join usersInRole in aspnet_UsersInRoles on aspUser.UserId equals usersInRole.UserId
join role in aspnet_Roles on usersInRole.RoleId equals role.RoleId
where role ...
select new { ... };
(Or you can use dot-form like myUser.AspUser.Roles.Role to let the ORM generate the joins if you prefer)
For performance, it's good to watch the SQL trace occasionally - make sure you're not making too many SQL round-trips for each logical step in code.
Hope that helps a bit.
Update - in answer to your questions about "should you even do that", I think "yes" but there are other options available - e.g. you can use Profile fields - see Step 6 in this great walkthrough - https://web.archive.org/web/20211020202857/http://www.4guysfromrolla.com/articles/120705-1.aspx
We have created EntityFramework entities for all of the AspNet membership tables, this lets us query them like any other entity.
Not sure if it is what your after but may help

Collection Exists Criteria in WCF Data Services

I'm trying to ask my OData service:
"Give me all the Products that do not have a Category"
with the Products and Category have a m2m relationship.
I've tried:
from p in Products
where p.Categories == null
select p
and
from p in Products
where !p.Categories.Any()
select p
and
from p in Products
where p.Categories.Count == 0
select p
but all of these give me not supported exceptions.
I'm not looking for alternatives or options. Please don't answer with other options.
My experience with WCF Data Services is that the client subset of LINQ to rest is lacking.
My biased option would be to just move it to server side where you have access to the full implementation of LINQ to entites? (or whatever you are using to implement your Data Service).
[WebGet]
public IQueryable<Products> GetProductsWithoutCategories(){
/*start psudo code
from p in Products
where p.Categories.Count == 0
select p
*/
}
This is not supported:
http://social.msdn.microsoft.com/Forums/en-US/adodotnetdataservices/thread/b505d630-c808-4bde-b08e-3ce1dd17f621/
The OData URL query language currently
doesn't support this type of query. As
a result the client's LINQ processor
doesn't support it either. If you
think it's valuable to add such
functionality please use our connect
site to suggest the feature, it makes
our planning job easier next time
around.
https://connect.microsoft.com/dataplatform/content/content.aspx?ContentID=15540&wa=wsignin1.0
As a workaround you could probably use
service operation. Define a service
operation which returns IQueryable (so
that you can compose some more query
operators on the result from the
client) and use the server side
provider to issues the query above.
My solution to this problem was to $expand the related field in the query, and then test if that field was empty or not...
JArray _array = (JArray)main_table_object["some_related_field"];
if (_array.Count > 0)
continue;
.. this is in the context of queries from Windows 7 phone to a WCF service using JSON as the message format.

Resources