The entity or complex type 'AdventureWorks2012Model.Product' cannot be constructed in a LINQ to Entities query - linq

As you can see, I got this error when I built Data Gird using Kendo UI. Does anybody could point out where I'm wrong in my code below.
private IEnumerable<Product> GetSubProduct()
{
var context = new AdvenDBEntities();
var subcate = context.Products.Select(p => new Product
{
ProductID = p.ProductID,
Name = p.Name,
Color = p.Color,
ListPrice = p.ListPrice,
}).ToList();
return subcate;
}
Error:
The entity or complex type 'AdventureWorks2012Model.Product' cannot be constructed in a LINQ to Entities query.
Thank you so much for your time!

Since Product is an entity of model, you are creating new object of this entity while selecting the records, which is NOT good idea, I am NOT sure how model will handle this kind of behaviour that is why it is preventing you to do so, (I guess). Anyway you can change the code to this,
private IEnumerable<Product> GetSubProduct()
{
var context = new AdvenDBEntities();
var subcate = context.Products.ToList();
return subcate;
}
BTW your function name indicating that you are missing a Where clause.
Also you can create some custom DTO class and use it instead.
E.g.
class ProductDTO
{
public int ProductID { get; set; }
public string Name { get; set; }
public string Color { get; set; }
public decimal ListPrice { get; set; }
}
private IEnumerable<ProductDTO> GetSubProduct()
{
var context = new AdvenDBEntities();
var subcate = context.Products.Select(p => new ProductDTO
{
ProductID = p.ProductID,
Name = p.Name,
Color = p.Color,
ListPrice = p.ListPrice,
}).ToList();
return subcate;
}

The first bad smell code I can point out for you. DBContext implements IDisposable so you are responsible for calling Dispose on it. In all, but one case in here, using block
You must build query to get all the product and then extract from it.
private IEnumerable<Product> GetSubProduct()
{
using (var context = new AdvenDBEntities())
{
// Get all constructed type product and then select from it
var subcate = context.Products
.ToList()
.Select(p => new Product
{
ProductID = p.ProductID,
Name = p.Name,
Color = p.Color,
ListPrice = p.ListPrice,
});
return subcate;
}
}

Related

How to write more efficient linq to entities query using EF6

I have an one-to-many relation in my entities:
public class Header
{
public Header()
{
Items = new List<Item>
}
public int Id {get; set;}
public virtual ICollection<Item> Items {get; set;}
// other properties
}
public class Item
{
public int Id {get; set;}
public virtual Header Header { get; set; }
public string Title { get; set; }
public DateTime CreationDate { get; set; }
public int Weight { get; set; }
}
I want to load Header and some of its Items, so I wrote this linq to entity query(EF6):
using(var ctx = new MyContext())
{
var result = ctx.Headers.Where(someConditions)
.AsNoTracking()
.Select(header => new {
HeaderId = header.Id,
//fetch other header properties here
LastItemCreationDate = header.Items.OrderByDescending(item => item.CreationDate)
.Select(item => item.Title)
.FirstOrDefault(),
LastItemTitle = header.Items.OrderByDescending(item => item.CreationDate)
.Select(item => item.CreationDate)
.FirstOrDefault(),
LastItemWeight = header.Items.OrderByDescending(item => item.CreationDate)
.Select(item => item.Weight)
.FirstOrDefault()
}).ToList();
}
This query generate a sql script with 3 times join Header and Item tables, is there any more efficent way to write this query to join Header and Item tables one time?
Since you are using Select, you don't need AsNoTracking since the resulting query will not load any entities. The key performance impacts in your case would be indexes in the Header table suitability for your Where clause, then also whether there is a Descending Index available on the CreationDate in the Items table.
Another improvement would be to alter the projection slightly:
var result = ctx.Headers.Where(someConditions)
.Select(header => new {
HeaderId = header.Id,
LatestItem = header.Items
.OrderByDescending(item => item.CreatedDate)
.Select(item => new
{
Title = item.Title,
CreationDate = item.CreationDate,
Weight = item.Weight
}).FirstOrDefault()
}).ToList();
This will change the resulting anonymous type structure a bit, but should result in a nicer, single join.
You will get a result.HeaderId, then a null-able result.LastestItem containing the latest item's properties. So result.LatestItem?.Title instead of result.Title.

Linq to entity - dynamic query

public void ApproveRowTable(string tablename, List<int> idValues)
{
foreach (var x in idValues)
{
var context = new SSPModel.sspEntities();
var genRules = (from a in context.GeneralRules
where a.ID == x
select a).SingleOrDefault();
genRules.Approved_by = GlobalClass.GlobalVar;
genRules.Approved_on = DateTime.Now;
context.SaveChanges();
}
}
In my query (from a in context.GeneralRules...) I would like to make it query base on a parameter (tablename) rather than i have to go and supply the name of the table in the query (as it is doing right now.). Any way i can get it to do that .. basic.. from a in context.TABLENAME -- TABLENAME is a parameter that is going to be passed when the function is called. Help
This will be difficult if your entity types do not all implement the same interface or derive from the same class. If they do, it's pretty simple:
// example base type, which your entities would need to implement
public interface IApprovable
{
public int ID {get; set;}
public string Approved_by {get; set;}
public DateTime Approved_on {get; set;}
}
//...
public void ApproveRowTable<T>(List<int> idValues)
where T : IApprovable
{
using(var context = new SSPModel.sspEntities())
{
var table = context.Set<T>();
var entities = table.Where(e => idValues.Contains(e.ID));
foreach(var entity in entities)
{
entity.Approved_by = GlobalClass.GlobalVar;
entity.Approved_on = DateTime.Now;
}
context.SaveChanges();
}
}
If your entity types do not implement a common base type, then you should modify them by creating empty partials which do implement it:
public partial class GeneralRule : IApprovable {}
If you cannot do that, then you can do something like the following. (I'm assuming ID is the PK, so we can use Find() rather than needing to build an expression:
public void ApproveTableRows(Type entityType, IEnumerable<int> idsToApprove)
{
using(var context = new SSPModel.sspEntities())
{
var set = context.Set(entityType);
if(set == null)
throw new ArgumentException("No DbSet found with provided name", "tableSetName");
var approveByProperty = entityType.GetProperty("Approved_by");
var approveOnProperty = entityType.GetProperty("Approved_on");
if(approveByProperty == null || approveOnProperty == null)
throw new InvalidOperationException("Entity type does not contain approval properties");
foreach (object id in idsToApprove)
{
var entityInstance = set.Find(id);
approveByProperty.SetValue(entityInstance, GlobalClass.GlobalVar);
approveOnProperty.SetValue(entityInstance, DateTime.Now);
}
context.SaveChanges();
}
}
As you can see, this is less efficient, as it issues a new query for each ID rather than getting them all at once. Also, the method accepts an entity Type rather than a string, to avoid the need to hunt down the right property by reflection. This could be improved, but really I think you should probably update your entities to implement a shared interface.
I assume you would like to have the method generic. When you are using EF all your tables are represented as objects, so you don't have to specify which table you want by name, just use a generic parameter.
I doubt that my solution is best, but it should work. But I have to warn you, reflection is slow and many times its usage is not right.
public void ApproveRowTable<T>(List<int> idValues)
{
var context = new SSPModel.sspEntities();
var table = context.GetType().GetProperties().OfType<T>().Single();
var genRules = (from a in table
where a.ID == x
select a).SingleOrDefault();
genRules.Approved_by = GlobalClass.GlobalVar;
genRules.Approved_on = DateTime.Now;
context.SaveChanges();
}

WP: How to use ToList() method for select multiple columns statement in linq to sql?

I selected 4 columns from my table by using select statement LINQ to SQL. Then I create a new List to store the query result. BUT, the code room.ToList(); is WRONG.
Why cannot we use "rooms_list = room.ToList()"?
How should we do to solve the problem???
Thanks for teaching me!
private void btnTest_Click(object sender, EventArgs e)
{
List<string> rooms_list = new List<string>();
using (LVDatabaseEntities database = new LVDatabaseEntities())
{
var room = from x in database.PHONGCHOIs
select new { x.TENPHONG, x.MATKHAUPHONG, x.CHUPHONG, x.SOLUONG };
rooms_list = room.ToList();
}
MessageBox.Show(rooms_list.Count.ToString());
}
Your rooms_list = room.ToList() is wrong, because it is not the List of type string.
To fix this, first create a class for a room
class Room
{
string TENPHONG { get; set; }
string MATKHAUPHONG { get; set; }
string CHUPHONG{ get; set; }
string SOLUONG{ get; set; }
}
Then, change your code like this
List<Room> rooms_list = new List<Room>();
using (LVDatabaseEntities database = new LVDatabaseEntities())
{
var rooms = from x in database.PHONGCHOIs
select new Room{
TENPHONG = x.TENPHONG,
MATKHAUPHONG = x.MATKHAUPHONG,
CHUPHONG = x.CHUPHONG,
SOLUONG = x.SOLUONG };
rooms_list = room.ToList();
}
MessageBox.Show(rooms_list.Count.ToString());
*Not tested. Let me know if anything didn't work

Select multiple columns in LINQ

I've written a LINQ query shown below :
List<Actions> actions = resourceActions.Actions.Select(s => s.ActionName).ToList();
How do I give for selecting multiple columns here ? ie I want to add columns s.ActionId and s.IsActive. I'm unable to apply it.
Make a class to represent the data you want:
public class ResourceAction
{
public int Id {get;set;}
public string Name {get; set; }
}
Select a list of those instead:
List<ResourceAction> actions = resourceActions.Actions
.Select(s => new ResourceAction() { Id = s.Id, Name = s.ActionName}).ToList();
I believe this is what your looking for. However you need to change the output to an anonymous type.
var actions = resourceActions.Actions.Select(s => new { s.ActionName, s.ActionId, s.IsActive } ).ToList();
You can use a anonymous type for this, for example
var actions = resourceActions.Actions.Select(s =>
new { Id = s.Id, Name = s.ActionName, Active = s.IsActive).ToList();
but a better way would be to create a class like
public class ActionWithId
{
public int Id { get; set; }
public string Name { get; set; }
public bool Active { get; set; }
}
List<ActionWithId> actions = resourceActions.Actions.Select(s =>
new ActionWithId() { Id = s.Id, Name = s.ActionName, Active = s.IsActive }).ToList();

linq count/groupby not working

I want to group by the categoryid and then do a count on this. But I don't know how to do this. I have tried a couple of ways without success. Here is my latest:
public class Count
{
public int TradersCount { get; set; }
public int Id { get; set; }
public string Description { get; set; }
}
public IQueryable<Count> CountTradersAttachedToCategories()
{
var data = from tc in _db.tblTradersCategories
select new Count
{
Description = tc.tblCategory.description,
Id = tc.tblCategory.categoryId,
TradersCount = tc.Select(x => x.categoryid).GroupBy().Count()
};
return data;
}
tblTradersCategories joins both
tblTraders/tblCategories
A single trader can have many categories
A single category can have many traders
Thanks in advance for any help.
Clare
Try this:
var data = from tc in _db.tblTradersCategories
group tc by new { tc.tblCategory.categoryId,
tc.tblCategory.description } into g
select new { Count = g.Count(),
Id = g.Key.categoryId,
Description = g.Key.description };
If you want that in your Count class you may need to use AsEnumerable() to perform the conversion in process:
var converted = data.AsEnumerable()
.Select(c => new Count { TradersCount = c.Count,
Id = c.Id,
Description = c.Description });
You can try doing them all in one go:
var data = from tc in _db.tblTradersCategories
group tc by new { tc.tblCategory.categoryId,
tc.tblCategory.description } into g
select new Count { TradersCount = g.Count,()
Id = g.Key.categoryId,
Description = g.Key.description };
But I don't know if that will work. It depends on how the LINQ provider handles it.

Resources