How do you re-use select statements with Entity Framework? - linq

Given the following query:
var query = from item in context.Users // Users if of type TblUser
select new User() // User is the domain class model
{
ID = item.Username,
Username = item.Username
};
How can I re-use the select part of the statement in other queries? I.e.
var query = from item in context.Jobs // Jobs if of type TblJob
select new Job() // Job is the domain class model
{
ID = item.JobId,
User = ReuseAboveSelectStatement(item.User);
};
I tried just using a mapper method:
public User MapUser(TblUser item)
{
return item == null ? null : new User()
{
ID = item.UserId,
Username = item.Username
};
}
With:
var query = from item in context.Users // Users if of type TblUser
select MapUser(item);
But if I do this, then the framework throws an error such as:
LINQ to Entities does not recognize
the method 'MapUser(TblUser)' method,
and this method cannot be translated
into a store expression.

You can't use regular function calls in a query definition like that. LINQ needs expression trees, it can't analyze compiled functions and magically translate that to SQL. Read this for a more elaborate explanation
The techniques used in the cited article are incorporated in linqkit (factoring out predicates) and might be of help, though I'm not sure you can use the same technique for managing projections, which is what you seem to want.
The more fundamental question you should ask yourself here IMHO is whether you really need this extra mapping layer? It seems like you're implementing something that EF is already perfectly capable of doing for you...

Try making your MapUser method static.

Related

In GraphQL, how to control DB query by client query?

I learn to use GraphQL these days. In my opinion, To build a query, I need to build three parts:
Schema
type User{
id String
name String
cars [Car!]!
}
type Car{
id String
}
type Query{
user(id: String): User
}
DB Query function
{
user: async function ({id}) {
const user = await DB.user.findOne({id});
const userCars = await DB.car.find({userId: id});
user.cars = userCars;
return cars;
}
}
Client query
{
user (id: "1") {
name
cars {
id
}
}
}
That query returns a user's name and his cars. The DB query function always query for cars.
But sometimes I just need user's info:
{
user (id: "1") {
name
}
}
I don't want to query for cars, so I hope to make my DB query function can auto choose to query for cars or not.
How can I do this?
GraphQL.js will support either object properties or methods for resolver functions; this is discussed in its page on Object Types.
One way to deal with this is just to insert an anonymous function directly into the returned object:
{
user: async function ({id}) {
const user = await DB.user.findOne({id});
user.cars = () => DB.car.find({userId: id});
return cars;
}
}
Another is to create a wrapper object with a class that provides the id property and (asynchronous, lazy) cars method; some examples of this are in the GraphQL.js documentation. This approach tends to work in most GraphQL implementations in most languages.
I think you looking into auto-creating/mapping from GraphQL query into db query.
Every queries are db/project specific, so you should create this mapping. You can easily do that with graphql-fields package.
There is copy pasted WHY section from the package:
An underlying REST api may only return fields based on query params.
{
user {
profile {
firstName
},
id
}
}
should request /api/user?fields=profile,id
while
{
user {
email
}
}
should request /api/user?fields=email
Implement your resolve method like so:
resolve(root, args, context, info) {
const topLevelFields = Object.keys(graphqlFields(info));
return fetch(`/api/user?fields=${topLevelFields.join(',')}`);
}
It's best to avoid squeezing it all into one resolver function. Instead, create a separate ObjectType for Cars which has its own fields and its own resolver function. This way, the car query is only called if that field is requested.
In case you are using a RDS, join monster and data louder can help optimize performance of your queries.
Join Monster which relies on generating one big join query and also solve the problem of only requesting exactly the fields you need from the DB
Cached and Batched SQL Data Source which uses facebook's dataloader under the hood - it wont solve the problem of which fields to query (although the example uses knex, which will make that a lot easier), but instead it can cache and batch your queries

How to show custom query result to view mvc3 Razor

I have Custom query Result as
public ActionResult Index()
{
var Query = (from E in db.SITE_MASTER.AsEnumerable()
where E.IS_PAGE == true
select new
{
E.POST_TITLE,
E.POST_TEXT
}).ToList();
return View(Query);
}
Now,
How can I make view for this result or How can I create View for this Result Query.
Thanks...
You can pass an anonymous type as a model, but please don't. It's ugly and will lead to maintenance problems.
As an alternative either use the ViewBag or create concrete type and pass that.

Joining asp_Users db tables in LINQ using asp.net MVC

I am working on an example asp.net project using MVC, but my database is a live one which I can't make changes to (technically it's the test version of this database but my point is changes to the database aren't possible).
I use the UserID from the asp_Users table to store who makes changes to various aspects of the system, and I want to start showing the user name in various front-end tables, but how do I link the tables to get this user name?
So to clarify, I'm going to want to do this for several tables throughout the system so I was hoping I could do it using LINQ.
I can get the info I want from using the join query, but how do I pass this to my View to use?
var plans = from users in db.aspnet_Users
join import in db.Plan_Imports
on users.UserId.ToString()
equals import.User_ID
select new
{
Date = import.Date,
UserName = users.UserName
};
Sample tables
asp_Users
UserID
UserName
...
table1
ID
field1
field2
...
User_ID <--- ref to asp_Users
table2
ID
field1
field2
...
User_ID <--- ref to asp_Users
I would create a ViewModel for each view.
ViewModel is just a POCO class
public class PlanViewModel
{
public string UserName { set;get;}
public DateTime ImportDate { set;get;}
}
Then Get the Data to this ViewModel/Collection of ViewModel using LINQ Projections from your query.
public ActionResutl Show()
{
var plans = (from users in db.aspnet_Users
join import in db.Plan_Imports
on users.UserId.ToString()
equals import.User_ID
select new PlanViewModel
{
ImportDate = import.Date,
UserName = users.UserName
}).ToList();
return View(plans);
}
Now Lets make our view strongly typed to a collection of our PlanViewModel
#model List<PlanViewModel>
#foreach(var plan in Model)
{
<p>#plan.UserName</p>
<p>#plan.ImportDate.ToString()</p>
}
The solution provided by Shyju worked perfectly, and it wasn't too complex to do, however I decided that I didn't think using LINQ was appropriate in this case as the code was getting out of hand for what should be a simple call.
What I did instead was use a stored procedure to get the information, and saved it to a complex object which I passed to my view.
The code is now much neater and easier to manage, as the code above became just
var plans = db.SP_SelectImports();
Read more about stored procedure mapping here: http://dotnet.dzone.com/news/mapping-stored-procedure

Linq Order By not working

The Linq query "order by" is not working and I've followed all the suggestions found on your site and other sites. Any assistance would be appreciated.
[WebGet]
public IQueryable<vw_providercharge_providers> GetChargeProviders(int submitted)
{
var results = (from p in this.CurrentDataSource.vw_providercharge_providers
where p.submitted == submitted
orderby p.fullname
select p);
return results;
}
Thanks for your input!
Yes, this is a WebGet method for a WCF data service. I get a 400 error if I don't return an IQueryable type, so I modified your suggestion a little. Unfortunately, it still seems to disregard any order-by.
[WebGet]
public IQueryable<vw_providercharge_providers> GetChargeProviders(int submitted)
{
var results = (from p in this.CurrentDataSource.vw_providercharge_providers
where p.submitted == submitted
orderby p.fullname
select p).ToArray();
results.OrderBy(p => p.patientname);
return results;
}
I notice you return an IQueryable<T> - are you calling any LINQ methods on the result before you enumerate it?
Not all LINQ methods preserve order. Most commonly, calling Distinct() after you do the ordering will destroy the order.
Since your method is a marked with a WebGet attribute, I'm assuming that you are calling this method from a Web endpoint, therefore you may need to collapse the collection prior to send it through internet.
Try:
[WebGet]
public vw_providercharge_providers[] GetChargeProviders(int submitted)
{
var results = (from p in this.CurrentDataSource.vw_providercharge_providers
where p.submitted == submitted
orderby p.fullname
select p).ToArray();
return results;
}
This way you have the guarantee that the GetChargeProviders method returns and array instead of an linq expression.
Regards,
I found the cause of the issue.
I had not set the "fullname" column as an Entity Key for the "vw_providercharge_providers" data model entity. Only the identity column was set as an Entity Key. I didn't realize that was a requirement to use it in an order by clause.
Thanks again for your input.

How to apply global filter on Entity Framework?

I have a table in my model named Customers with a field IsActive. Whenever I run a query on Customers, only the active customers should be retrieved. I can include the filter in every query, but that doesn't look very. I would like to be able to override the Customers property at the Object Context lever, but I am not sure if this is possible. Any help would be very appreciated! Thanks
Although a late response, I will put it here so it can help others.
You can also set a condition for your entity in your edmx file. Select your entity and Goto Mapping Details and create a new condition.
Maybe you could declare new property and use it:
public partial class MyEntities
{
public ObjectQuery<User> ActiveCustomers
{
get
{
return Customers.Where(c => c.IsActive);
}
}
}
I don't know why this is problem for you. You can put one query inside some function:
IEnumerable<Customers> GetActiveCustomers()
{
var activeCustomers =
from cust in db.Customers
where cust.IsActive == true
select cust;
return activeCustomers;
}
And call it every time you like. You can even put active customers in some private List or even better ObservableCollection. Then you can query your result again:
var myCustomers =
from cust in GetActiveCustomers()
where cust.CustomerName == "John"
select cust;
and that's it.
All you need to do is retrieve all of the customers no matter if they are active or not and then use a
foreach(Customer c in Results)
{
if(c.IsActive)
listofactivecustomers.Add(c);
}

Resources