I have a domain class like below :
public class Employee
{
public int EmployeeId { get; set; }
public int DeptId { get; set; }
}
public class Transaction
{
public int TRID { get; set; }
public int EmployeeId { get; set; }
public string Status { get; set; }
}
Now I want to get all employees from the EmployeeTable for DeptId = 100. I want to calculate Pending status for those employees whose transactions are pending.
So if employee records are found in Transactions table then just want to return a column saying whether employee has any pending transactions or not)
Query :
var t = (from e in _employeeRepository.GetAll() //returns IQueryable<Employee>
where e.DeptId == 100
from t in _transactionRepository.GetAll().Where(t => t.EmployeeId == e.EmployeeId)
select new
{
IsPendingTransaction = (t != null && t.Status != "Done") ? true : false,
}).ToList();
Error : LINQ to Entities does not recognize the method
'System.Linq.IQueryable`1[Transaction] GetAll()' method, and this
method cannot be translated into a store expression."}
Sql Query :
SELECT e.*
(CASE WHEN (t.EmployeeId is not null and t.Status <> 'Done')
THEN CAST(1 AS BIT)
ELSE CAST(0 AS BIT)
End) as IsPendingTransaction
FROM Employee e OUTER APPLY
(SELECT t.*
FROM Transactions t
WHERE e.EmployeeId = t.EmployeeId
) t
WHERE e.DeptId = 100;
The issue is that when you work within IQueryable, every statement inside that Linq expression must be understood by EF to be able to be translated to SQL.
Your first repository call returns an IQueryable<Employee> which you are trying to extend by telling it to join on some code called "_transactionRepository.GetAll()" EF doesn't know what this is, it doesn't correlate to mapped DbSets or properties on entities...
If your Transaction entity has a navigation property back to Employee (which it should) you should be able to accomplish what you want using just the TransactionRepository with something like:
var t = _transactionRepository.GetAll()
.Where(t => t.Employee.DeptId == 100)
.Select(t => new
{
IsPendingTransaction = (t != null && t.Status != "Done") ? true : false
}).ToList();
Using IQueryable<TEntity> in a repository pattern can be quite powerful, however I don't recommend adopting a Generic repository pattern as it just serves to fragment your thinking when working with entities and their relationships with one another, allowing EF to manage the resulting SQL without you resorting to pre-emptively trying to do the joining yourself, often causing conflicts with what EF is capable of working out itself.
Edit: Ok, from your description to get a list of employees with a flag if they have a pending transaction: That would be back at the Employee level with a query something like:
var employees = _employeeRepository.GetAll()
.Where(e => e.DeptId == 100)
.Select(e =>
{
Employee = e,
HasPendingTransaction = e.Transactions.Any(t => t.Status != "Done")
}).ToList();
Or projected to a ViewModel to embed the HasPendingTransaction alongside the Employee details:
var employees = _employeeRepository.GetAll()
.Where(e => e.DeptId == 100)
.Select(e => new EmployeeDetailsViewModel
{
EmployeeId = e.EmployeeId,
Name = e.Name,
// include other relevent details needed for the view...
HasPendingTransaction = e.Transactions.Any(t => t.Status != "Done")
}).ToList();
The advantage of projection is you can build more efficient / faster queries that reduce the amount of data sent over the wire and avoid issues like lazy load trips if you try to serialize entities to the view.
Fix Transaction class
public class Transaction
{
public int TRID { get; set; }
public string Status { get; set; }
public int EmployeeId { get; set; }
public virtual Employee Employee { get; set; }
}
It is not the best idea to have a separate repository for each entity since query usually consists from several entities. It is better to make a join using dbcontext then several repository queries as you trying to do. Don't try to create a base generic repository also. Sooner or later you will see that is is not very helpfull. So add in one of your repositories (probably EmployeeRepository) query like this
var employees= dbcontext.Transactions
.Where(t=> t.Employee.DeptId == 100 && t.EmployeeId==employeeId)
.Select (t=> new {
EmployeeName= t.Employee.Name,
IsPendingTransaction = (t.Status != null && t.Status != "Done") ? true : false}).ToList()
Good day,
I have a model class like below
public class EmployeeModel
{
[Key]
public int employeeId{get;set;}
public string Fullname {get;set;}
public string Address{get;set;}
public ICollection<PaymentModel> Payments {get;set;}
}
public class PaymentModel
{
[Key]
public int PaymentId{get; set;}
public int employeeId{get; set;}
public decimal PaymentAmount{get; set;}
public int IsPosted {get; set;}
public virtual EmployeeModel Employee {get; set;}
}
i just want to query the list of employee together with their list of payments using linq. so i code like this:
dbcontext db = new dbcontext();
var listing = from d in db.Employees
.include("Payments")
select d;
this listing show the all of the employee and all its payments.
but i need to filter each employee Payments that IsPosted = 1
so as initial answer, ill do this code;
dbcontext db = new dbcontext();
List<EmployeeModel> FinalList = new List<EmployeeModel>();
var listingofEmp = db.employee.ToList();
foreach(EmployeeModel emp in listingofEmp){
emp.Payments= db.payments.where(x => x.IsPosted == 1).ToList();
FinalList.Add(emp);
}
my Question is, is ther any other way to code it much easier? something like this.
dbcontext db = new dbcontext();
var listing = from d in db.Employees
.include(d => x.Payments.IsPosted == 1)
select d;
im curently using entityframework 5
ive research regarding it not work for me Link
Hope someone will help me
Thanks In Advance Guys
What are you asking for is not natively supported, so there is no easier way, but for sure there is more efficient way because your current code is performing N + 1 database queries.
A better way could be to retrieve employees and related filtered payments with one database query using anonymous type projection, and then do something similar to your approach to create the final result in memory. For instance:
var listing =
db.Employees.Select(employee => new
{
employee,
payments = employee.Payments.Where(p => p.IsPosted == 1)
})
.AsEnumerable() // Switch to LINQ to Objects
.Select(r =>
{
r.employee.Payments = r.payments.ToList();
return r.employee;
})
.ToList();
it colud be a good alternative
var listing = from d in db.Payments
.include("Employees")
.where d.IsPosted == 1
select d.Employees;
(not tested, then please fix mistakes)
start from pyaments, filter for is posted=1
, then select related emplyees
Try something like this: It will give you a list of anonymous type that will hold the employee and it's payments.
using (dbcontext ctx = new dbcontext())
{
ctx.Connection.Open();
var result = (from e in ctx.Employees
join p in ctx.Payments on e.employeeId equals p.employeeId
where p.IsPosted == 1
select new
{
Employee = e,
Payments = p
}).ToList();
ctx.Connection.Close();
}
I would like to return some data from 2 related tables. I have a one to many relationship. One WebLead can have many Pricing records. I would like to return the data for the WebLead and the data for most recent record inserted into the Pricing table.
I am new to LINQ and EF. Here is what I have so far but this is only returning the WebLeads table data...What am I missing? Do I need to add a FirstOrDefault for the Pricing table?
var priceRefi = db.WebLeads.Include(p => p.Pricings)
.Where(l => l.LoanAgent.Equals(LoanAgent) && l.LeadStatus.Equals("Priced");
then to populate the view model:
PricedRefiLeads = priceRefi.ToList(),
UPDATE: I am sorry I left so much out. I updated my query to the following (LoanAgent is just a string parameter)
var priceRefi = from lead in db.WebLeads
where lead.LoanAgent == LoanAgent && lead.LeadStatus == "Priced"
select new LeadWithLastPricing()
{
Lead = lead,
LastPricing = lead.Pricings.OrderByDescending(x => x.PricingDate).FirstOrDefault()
};
I then want to take the results of that query and return it as a list to my view model:
var viewModel = new PipelineViewModel
{
////
PricedRefiLeads = priceRefi.ToList(),
}
I am seeing the following error on the priceRefi.ToList():
Cannot implicitly convert type
'System.Collections.Generic.List(LoanModule.ViewModels.LeadWithLastPricing)'
to 'System.Collections.Generic.List(LoanModule.Models.WebLead)
I am new to MVC. As I read this error, I understand that I must be missing something in my PipelineViewModel but I am not sure what that is.
In PipelineViewModel, I do have:
public List<WebLead> PricedRefiLeads { get; set; }
What am I missing? Forgive me if I left information out, I am struggling to wrap my head around this.
I am using a number of assumptions, for information not specifically mentioned in your question:
LoanAgent is a (local) string variable representing the agent you want to filter on.
Pricing has a field named PricingDate that is of type DateTime.
Then you can do it like this:
// I am assuming a Pricing has a DateTime field named "PricingDate"
var priceRefi =
from lead in WebLeads
where lead.LoanAgent == LoanAgent && lead.LeadStatus == "Priced"
select new {
Lead = lead,
LastPricing = lead.Pricings.OrderByDescending(x => x.PricingDate).FirstOrDefault()
};
Note that this returns an anonymous object as the projection result. If you want to pass this result on, you should create a class:
public class LeadWithLastPricing
{
public Lead Lead { get; set; }
public Pricing LastPricing { get; set; }
}
And do the select part like this:
// ...
select new LeadWithLastPricing() {
Lead = lead,
LastPricing = lead.Pricings.OrderByDescending(x => x.PricingDate).FirstOrDefault()
};
For your second error, change this:
public List<WebLead> PricedRefiLeads { get; set; }
To
public List<LeadWithLastPricing> PricedRefiLeads { get; set; }
And use it like:
var viewModel = new PipelineViewModel
{
PricedRefiLeads = priceRefi.ToList(),
}
You can try:
var query =
from l in db.WebLeads
let maxDate = l.Pricings.Max(p => p.InsertDate)
where l.LoanAgentID == someLoanAgentID
&& l.LeadStatus == "Priced"
select new { Lead = l, Pricing = l.Pricings.FirstOrDefault(x => x.InsertDate == maxDate) };
This will give objects with two properties: Lead and Pricing which are WebLead and Pricings objects. Please forgive syntax errors this is streight out of notepad.
Edit: I suppose I should tell you how to use the result object:
foreach (var MyLead in query)
{
string customerName = MyLead.Lead.CustomerName; // i.e. some property of WebLead
DateTime InsertDate = MyLead.Pricing.InsertDate; // i.e. some property of Pricings
}
You can project directly into a WebLead instead of creating a new class, by doing the following:
var priceRefi = db.WebLeads
.Include(p => p.Pricings)
.Where(l => l.LoanAgent == LoanAgent)
.Where(l => l.LeadStatus == "Priced")
.Select(lead=>new WebLead {
lead.LoanAgent,
lead.LeadStatus,
...,
Pricings=lead.Pricings.OrderByDescending(x=>x.PricingDate).Take(1)});
I have two models, Benefit and SchemeName
Benefit -
[Key]
public int BenefitID { get; set; }
public string BenefitName { get; set; }
public string BenefitDescription { get; set; }
public virtual ICollection<SchemeName> SchemeNames { get; set; }
SchemeName
[Key]
public int SchemeNameID { get; set; }
public string Name { get; set; }
public virtual ICollection<Benefit> Benefits { get; set; }
This has created three tables in the database Benefits, SchemeNames and a joining table called SchemeNameBenefits.
I am trying to populate a droplownlist that contains only the SchemeNames associated with a certain Benefit but am not sure how I can do this, can I reference the join table in my code?
I started with the following (which returns all SchemeNames)
private void PopulatePensionSchemeName(object selectedPensionSchemeName = null)
{
var schemeNameQuery = from d in db.SchemeNames
orderby d.SchemeNameID
select d;
ViewBag.PensionSchemeNameID = new SelectList(schemeNameQuery, "SchemeNameID", "Name", selectedPensionSchemeName);
}
But I'm not sure how I can add this clause. Any pointers?
You'll need the key of the Benefit object you want the SchemeNames for. The query you're probably looking for is:-
var benefitId = // However you get your benefit Id
var schemaNameQuery = from b in db.Benefits
from s in b.SchemeNames
where b.BenefitId == benefitId
select s;
Or in the extension method syntax:-
var schemaNameQuery = db.Benefits.Where(b.BenefitId == benefitId)
.SelectMany(b => b.SchemeNames);
Which produces the following SQL:-
SELECT ...
FROM [dbo].[SchemeNameBenefits] AS [Extent1]
INNER JOIN [dbo].[SchemeNames] AS [Extent2]
ON [Extent1].[SchemeName_Id] = [Extent2].[SchemeNameId]
WHERE [Extent1].[Benefit_Id] = #p__linq__0
Alternately you can use:-
var benefitId = // However you get your benefit Id
var schemeNameQuery = from d in db.SchemeNames
where d.Benefits.Any(x => x.Id == benefitId)
orderby d.SchemeNameId
select d;
This produces the following SQL:-
SELECT ...
FROM ( SELECT ... FROM [dbo].[SchemeNames] AS [Extent1]
WHERE EXISTS (SELECT 1 AS [C1]
FROM [dbo].[SchemeNameBenefits] AS [Extent2]
WHERE ([Extent1].[SchemeNameId] = [Extent2].[SchemeName_Id])
AND ([Extent2].[Benefit_Id] = #p__linq__0)))
AS ...
ORDER BY [Project2].[Id] ASC
Note that in both cases the generated SQL references your junction table even though it isn't part of your EF model.
If you already have the Benefit object, of course, you can get its SchemeNames more simply by using:-
var schemeNameQuery = benefit.SchemeNames;
I would do this by using a Junction Table. The Junction Table is your Joining Table. It will consist of two foreign Keys, SchemeNameID & BenefitID.
Check out this website for more on Junction Tables:
http://megocode3.wordpress.com/2008/01/04/understanding-a-sql-junction-table/
It helped me out a lot.
[Disclaimer] Conditional on there existing or adding the SchemeNameBenefits model the following should work.
So it seems like the SchemeNameBenefits table is a many-to-many map, in this case use the benefit ID to get a collection of scheme ID's
var schemeIds = db.SchemeNamesBenefits.Where(map => map.BenefitID == id)
.Select(map => map.SchemeNameID).ToArray();
Then pull back all the scheme name information for these scheme ID's
var result = db.SchemeNames.Where(scheme => schemeIds.Contains(scheme.SchemeNameID))
.OrderBy(scheme => scheme.SchemeNameId)
.Select(scheme => scheme.Name).ToArray();
Or in one query
var result = db.SchemeNamesBenefits.Where(map => map.BenefitID == id)
.SelectMany(map => db.SchemeNames
.Where(scheme => map.SchemeNameID == scheme.SchemeNameID)
.OrderBy(scheme => scheme.SchemeNameId)
.Select(scheme => scheme.Name)
.AsEnumerable())
.ToArray()
There is an entity type called Product that is generated by entity framework.
I have written this query
public IQueryable<Product> GetProducts(int categoryID)
{
return from p in db.Products
where p.CategoryID== categoryID
select new Product { Name = p.Name};
}
The code below throws the following error :
"The entity or complex type Shop.Product cannot be constructed in a
LINQ to Entities query"
var products = productRepository.GetProducts(1).Tolist();
But when I use select p instead of select new Product { Name = p.Name}; it works correctly.
How can I preform a custom select section?
You cannot (and should not be able to) project onto a mapped entity. You can, however, project onto an anonymous type or onto a DTO:
public class ProductDTO
{
public string Name { get; set; }
// Other field you may need from the Product entity
}
And your method will return a List of DTO's.
public List<ProductDTO> GetProducts(int categoryID)
{
return (from p in db.Products
where p.CategoryID == categoryID
select new ProductDTO { Name = p.Name }).ToList();
}
You can project into anonymous type, and then from it to model type
public IEnumerable<Product> GetProducts(int categoryID)
{
return (from p in Context.Set<Product>()
where p.CategoryID == categoryID
select new { Name = p.Name }).ToList()
.Select(x => new Product { Name = x.Name });
}
Edit: I am going to be a bit more specific since this question got a lot of attention.
You cannot project into model type directly (EF restriction), so there is no way around this. The only way is to project into anonymous type (1st iteration), and then to model type (2nd iteration).
Please also be aware that when you partially load entities in this manner, they cannot be updated, so they should remain detached, as they are.
I never did completely understand why this is not possible, and the answers on this thread do not give strong reasons against it (mostly speaking about partially loaded data). It is correct that in partially loaded state entity cannot be updated, but then, this entity would be detached, so accidental attempts to save them would not be possible.
Consider method I used above: we still have a partially loaded model entity as a result. This entity is detached.
Consider this (wish-to-exist) possible code:
return (from p in Context.Set<Product>()
where p.CategoryID == categoryID
select new Product { Name = p.Name }).AsNoTracking().ToList();
This could also result in a list of detached entities, so we would not need to make two iterations. A compiler would be smart to see that AsNoTracking() has been used, which will result in detached entities, so it could allow us to do this. If, however, AsNoTracking() was omitted, it could throw the same exception as it is throwing now, to warn us that we need to be specific enough about the result we want.
There is another way that I found works, you have to build a class that derives from your Product class and use that. For instance:
public class PseudoProduct : Product { }
public IQueryable<Product> GetProducts(int categoryID)
{
return from p in db.Products
where p.CategoryID== categoryID
select new PseudoProduct() { Name = p.Name};
}
Not sure if this is "allowed", but it works.
Here is one way to do this without declaring aditional class:
public List<Product> GetProducts(int categoryID)
{
var query = from p in db.Products
where p.CategoryID == categoryID
select new { Name = p.Name };
var products = query.ToList().Select(r => new Product
{
Name = r.Name;
}).ToList();
return products;
}
However, this is only to be used if you want to combine multiple entities in a single entity. The above functionality (simple product to product mapping) is done like this:
public List<Product> GetProducts(int categoryID)
{
var query = from p in db.Products
where p.CategoryID == categoryID
select p;
var products = query.ToList();
return products;
}
Another simple way :)
public IQueryable<Product> GetProducts(int categoryID)
{
var productList = db.Products
.Where(p => p.CategoryID == categoryID)
.Select(item =>
new Product
{
Name = item.Name
})
.ToList()
.AsQueryable(); // actually it's not useful after "ToList()" :D
return productList;
}
You can use this and it should be working --> You must use toList before making the new list using select:
db.Products
.where(x=>x.CategoryID == categoryID).ToList()
.select(x=>new Product { Name = p.Name}).ToList();
In response to the other question which was marked as duplicate (see here) I figured out a quick and easy solution based on the answer of Soren:
data.Tasks.AddRange(
data.Task.AsEnumerable().Select(t => new Task{
creator_id = t.ID,
start_date = t.Incident.DateOpened,
end_date = t.Incident.DateCLosed,
product_code = t.Incident.ProductCode
// so on...
})
);
data.SaveChanges();
Note:
This solution only works if you have a navigation property (foreign key) on the Task class (here called 'Incident').
If you don't have that, you can just use one of the other posted solutions with "AsQueryable()".
You can solve this by using Data Transfer Objects (DTO's).
These are a bit like viewmodels where you put in the properties you need and you can map them manually in your controller or by using third-party solutions like AutoMapper.
With DTO's you can :
Make data serialisable (Json)
Get rid of circular references
Reduce networktraffic by leaving properties you don't need (viewmodelwise)
Use objectflattening
I've been learning this in school this year and it's a very useful tool.
If you are using Entity framework, then try removing property from DbContext which uses your complex model as Entity
I had same problem when mapping multiple model into a viewmodel named Entity
public DbSet<Entity> Entities { get; set; }
Removing the entry from DbContext fixed my error.
if you are Executing Linq to Entity you can't use the ClassType with new in the select closure of query only anonymous types are allowed (new without type)
take look at this snippet of my project
//...
var dbQuery = context.Set<Letter>()
.Include(letter => letter.LetterStatus)
.Select(l => new {Title =l.Title,ID = l.ID, LastModificationDate = l.LastModificationDate, DateCreated = l.DateCreated,LetterStatus = new {ID = l.LetterStatusID.Value,NameInArabic = l.LetterStatus.NameInArabic,NameInEnglish = l.LetterStatus.NameInEnglish} })
^^ without type__________________________________________________________________________________________________________^^ without type
of you added the new keyword in Select closure even on the complex properties you will got this error
so remove the ClassTypes from new keyword on Linq to Entity queries ,,
because it will transformed to sql statement and executed on SqlServer
so when can I use new with types on select closure?
you can use it if you you are dealing with LINQ to Object (in memory collection)
//opecations in tempList , LINQ to Entities; so we can not use class types in select only anonymous types are allowed
var tempList = dbQuery.Skip(10).Take(10).ToList();// this is list of <anonymous type> so we have to convert it so list of <letter>
//opecations in list , LINQ to Object; so we can use class types in select
list = tempList.Select(l => new Letter{ Title = l.Title, ID = l.ID, LastModificationDate = l.LastModificationDate, DateCreated = l.DateCreated, LetterStatus = new LetterStatus{ ID = l.LetterStatus.ID, NameInArabic = l.LetterStatus.NameInArabic, NameInEnglish = l.LetterStatus.NameInEnglish } }).ToList();
^^^^^^ with type
after I executed ToList on query it became in memory collection so we can use new ClassTypes in select
In many cases, the transformation is not needed. Think for the reason you want the strongly type List, and evaluate if you just want the data, for example, in a web service or for displaying it. It does not matter the type.
You just need to know how to read it and check that is identical to the properties defined in the anonymous type that you defined. That is the optimun scenario, cause something you don't need all the fields of an entity, and that's the reason anonymous type exists.
A simple way is doing this:
IEnumerable<object> list = dataContext.Table.Select(e => new { MyRequiredField = e.MyRequiredField}).AsEnumerable();
It won't let you map back onto Product since that is your table you are querying. You need an anonymous function, then you can add it to a ViewModel, and add each ViewModel to a List<MyViewModel> and return these. It's a slight digression, but I include caveats about handling nullable dates because these are a pain in the behind to deal with, just in case you have any. This is how I handled it.
Hopefully you have a ProductViewModel:
public class ProductViewModel
{
[Key]
public string ID { get; set; }
public string Name { get; set; }
}
I have dependency injection/repository framework where I call a function to grab my data. Using your post as an example, in your Controller function call, it would look like this:
int categoryID = 1;
var prods = repository.GetProducts(categoryID);
In the repository class:
public IEnumerable<ProductViewModel> GetProducts(int categoryID)
{
List<ProductViewModel> lstPVM = new List<ProductViewModel>();
var anonymousObjResult = from p in db.Products
where p.CategoryID == categoryID
select new
{
CatID = p.CategoryID,
Name = p.Name
};
// NOTE: If you have any dates that are nullable and null, you'll need to
// take care of that: ClosedDate = (DateTime?)p.ClosedDate ?? DateTime.Now
// If you want a particular date, you have to define a DateTime variable,
// assign your value to it, then replace DateTime.Now with that variable. You
// cannot call a DateTime.Parse there, unfortunately.
// Using
// new Date("1","1","1800");
// works, though. (I add a particular date so I can edit it out later.)
// I do this foreach below so I can return a List<ProductViewModel>.
// You could do: return anonymousObjResult.ToList(); here
// but it's not as clean and is an anonymous type instead of defined
// by a ViewModel where you can control the individual field types
foreach (var a in anonymousObjResult)
{
ProductViewModel pvm = new ProductViewModel();
pvm.ID = a.CatID;
pvm.Name = a.Name;
lstPVM.Add(rvm);
}
// Obviously you will just have ONE item there, but I built it
// like this so you could bring back the whole table, if you wanted
// to remove your Where clause, above.
return lstPVM;
}
Back in the controller, you do:
List<ProductViewModel> lstProd = new List<ProductViewModel>();
if (prods != null)
{
// For setting the dates back to nulls, I'm looking for this value:
// DateTime stdDate = DateTime.Parse("01/01/1800");
foreach (var a in prods)
{
ProductViewModel o_prod = new ReportViewModel();
o_prod.ID = a.ID;
o_prod.Name = a.Name;
// o_prod.ClosedDate = a.ClosedDate == stdDate ? null : a.ClosedDate;
lstProd.Add(o_prod);
}
}
return View(lstProd); // use this in your View as: #model IEnumerable<ProductViewModel>
only add AsEnumerable() :
public IQueryable<Product> GetProducts(int categoryID)
{
return from p in db.Products.AsEnumerable()
where p.CategoryID== categoryID
select new Product { Name = p.Name};
}
you can add AsEnumerable to your collection like the follow :
public IQueryable<Product> GetProducts(int categoryID)
{
return from p in db.Products.AsEnumerable()
where p.CategoryID== categoryID
select new Product { Name = p.Name};
}