The entity cannot be constructed in a LINQ to Entities query - c#

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};
}

Related

Is it possible to reuse parts of a LINQ to Entities select statement?

When using LINQ to Entities, is there a way to reuse a block of a select statment in other select stements?
For example, in the below code, I'm using LINQ to select a customer device object from my database. I also select a related Model object from a table that is joined to the customer devices table.
list = context.PTT_CUSTOMER_DEVICES
.Include(...)
.Select(d => new CustomerDevice
{
customerAssetTag = d.CustomerAssetTag,
customerDeviceID = d.CustomerDeviceID,
//This section is used in several LINQ statements throughout the application.
Model = new Model()
{
ModelID = d.PTS_MODELS.ModelID,
Name = d.PTS_MODELS.Name,
Make = new Make()
{
MakeID = d.PTS_MODELS.PTS_MAKES.MakeID,
Name = d.PTS_MODELS.PTS_MAKES.Name
}
}
})...
There are, however, other objects in the database that also reference the Model table. In my select statements for those other tables, I basically copied the same Model = new Model() code to a select statement for those different tables.
What I'm wondering is, is it possible to store and reuse that block of code in multiple selects? Possibly using an extension method?
As an alternative to Func<>s, you can also make use of extension methods to reuse the conversions between your entity types to and other POCOs.
public static IQueryable<CustomerDevice> ToCustomerDevice(this IQueryable<PTT_CUSTOMER_DEVICES> devices)
{
return devices.Select(d => new CustomerDevice
{
customerAssetTag = d.CustomerAssetTag,
customerDeviceID = d.CustomerDeviceID
}
}
However, EF will not allow you to nest these, and will complain that it cannot convert the nested extension method to SQL.
A work around for this can be to perform the transform in memory, rather than in SQL:
public static Model ToModel(this PTS_MODELS model)
{
return new Model()
{
ModelID = model.ModelID,
Name = model.Name,
Make = new Make()
{
MakeID = model.PTS_MAKES.MakeID,
Name = model.PTS_MAKES.Name
}
};
}
public static IEnumerable<CustomerDevice> ToCustomerDevice(this IQueryable<PTT_CUSTOMER_DEVICES> devices)
{
return devices
.Include(d => d.PTS_MODELS.PTS_MAKES)
.AsEnumerable() // Evaulate everything that follows in memory
.Select(d => new CustomerDevice
{
customerAssetTag = d.CustomerAssetTag,
customerDeviceID = d.CustomerDeviceID,
Model = d.PTS_MODELS.ToModel()
});
}
Since you are now returning an IEnumerable<> any further Where() conditions will be evaluated in memory, rather than in SQL, so its important that ToCustomerDevice() is your last call.
If those tables have a common base class or implement the same interface you can do it.
To make it simple assume I have a IQueryable<string> names. I can sort it like this:
IQueryable<string> sorted = names.OrderBy(name => name);
But if I want to keep this particular sort to use later I can do this:
Func<IQueryable<string>, IQueryable<string>> orderBy = q => q.OrderBy(x => x);
Now to call it I just pass any IQueryable<string> in:
IQueryable<string> sorted = orderBy(names);
You would need to create a constructor for Model that takes a CustomerDevice? (what ever the entity is for PTT_CUSTOMER_DEVICES:
public Model(CustomerDevice d) {
ModelID = d.PTS_MODELS.ModelID;
Name = d.PTS_MODELS.Name;
Make = new Make() {
MakeID = d.PTS_MODELS.PTS_MAKES.MakeID,
Name = d.PTS_MODELS.PTS_MAKES.Name
};
}
Then you could just call that constructor in the LINQ:
Model = new Model(d),
You can use Expression:
public static Expression<Func<PTT_CUSTOMER_DEVICES, CustomerDevice>>
CustomerDeviceExpression = d =>
new CustomerDevice
{
customerAssetTag = d.CustomerAssetTag,
customerDeviceID = d.CustomerDeviceID,
Model = new Model()
{
ModelID = d.PTS_MODELS.ModelID,
Name = d.PTS_MODELS.Name,
Make = new Make()
{
MakeID = d.PTS_MODELS.PTS_MAKES.MakeID,
Name = d.PTS_MODELS.PTS_MAKES.Name
}
}
};
Then:
list = context.PTT_CUSTOMER_DEVICES
.Include(...)
.Select(CustomerDeviceExpression)...

left outer join in BAL using repository pattern - null exception

I don't quite understand why the following syntax, runs fine directly to Entity Framework.
var query = (from c in entitites.car
join cat in entitites.categories on c.code equals cat.code into categoriesGroup
from cg in categoriesGroup.DefaultIfEmpty()
select new CarListModel
{
Car = c,
CategoryDescription = cg == null ? null : cg.Description
});
var test = query.ToList(); //Success
While doing the same query on iqueryables from my repository fails with "The argument to DbIsNullExpression must refer to a primitive, enumeration or reference type." The repository uses the same entities object.
var queryCars = carRepository.GetIQueryable();
var queryCategory = categoryRepository.GetIQueryable();
var query = (from c in queryCars
join cat in queryCategory on c.Code equals cat.Code into categories
from cg in categories.DefaultIfEmpty()
select new CarListModel
{
Car = c,
CategoryDescription = cg == null ? null : cg.Description
});
var test = query.ToList(); // Fails!!!
Using the repository pattern, it does work if I change the syntax to
...
CategoryDescription = cg.Description
But if I mock up the repositories from List it failes with Object reference not set to an instance of an object.
I believe this has something do to with materialized / non-materialized data.
The .DefaultIfEmpty clearly returns a different result in these examples, and I was thinking of overriding with always returning NULL if empty. Not sure how I would go about this either.
The idea is to isolate the business logic to a service layer, and not in the repository. Though perhaps joining tables is "not" BL, and is fine in repository? How to do complex joins using this pattern?
Is is it not possible to do IQueryable joins using the repositories?
Update!
Added an example of the GetIQueryable method from the repository
public class Category
{
Public string Code {get;set;}
Public string Description {get; set;}
}
public IQueryable<Category> GetIQueryable()
{
return (from c in entities.categories
select new Category
{
Code = c.code,
Description = c.descripton
}).AsQueryable();
}
Problem is here:
public IQueryable<Category> GetIQueryable()
{
return (from c in entities.categories
select new Category
{
Code = c.code,
Description = c.descripton
}).AsQueryable();
}
You can't use new Category in query, because Category is your data model class (mapped to table). You have 2 options:
Rewrite query without new:
public IQueryable<Category>GetIQueryable()
{
return (from c in entities.categories
select c).AsQueryable();
}
Use another DTO objects as result:
class CategoryDto
{
public int Code {get;set;}
public string Description {get;set;}
}
//...
public IQueryable<CategoryDto> GetIQueryable()
{
return (from c in entities.categories
select new CategoryDto
{
Code = c.code,
Description = c.descripton
}).AsQueryable();
}

NHibernate select a list of objects with related child objects with QueryOver

I'm having trouble with something that is probably very simple.
In my database I have the following tables:
tblOrder
-----------------
Id
OrderStatusId
tblOrderStatus
-----------------
Id
Name
And I have made the following mappings in my project:
[Class(NameType = typeof(Order), Table = "tblOrder")
public class Order {
[Id(-2, Name = "Id")]
[Generator(-1, Class = "native")]
public virtual long Id { get; set; }
[ManyToOne]
public virtual OrderStatus Status { get; set; }
}
[Class(NameType = typeof(OrderStatus), Table = "tblOrderStatus")]
public class OrderStatus {
[Id(-2, Name = "Id")]
[Generator(-1, Class = "native")]
public virtual long Id { get; set; }
[Property]
public virtual string Name { get; set; }
}
The query should return a IList<OrderSummary>. I want the class OrderSummary to have a property Status where Status is an object with an Id and a Name property. This could be either with a KeyValuePair or of type OrderStatus (whichever is best and works). Fetching the orders is not a problem but adding the OrderStatus as an object with said properties is the part I'm having trouble with.
I also need to return the result of the query as JSON to the client.
OrderSummary should look like this:
public class OrderSummary {
public long Id { get; set; }
public OrderStatus Status { get; set; }
}
In my first version OrderSummary had separate properties for OrderStatusId and OrderStatusName. This works but I'm trying to avoid these separate properties.
I have also tried this with SelectSubQuery but this returns an error because it returns more than one field in a subquery.
----------------------------------- UPDATE -----------------------------
Following Fredy Treboux's advice I changed my query using Eager which result in the following query:
var query = session.QueryOver<OrderStatus>
.Fetch(o => o.Status).Eager
.JoinAlias(o => o.Status, () => statusAlias, JoinType.LeftOuterJoin);
The problem is, I found out, is not selecting the data but how to convert the retrieved Status and assign it to OrderSummary.Status? I have tried the following:
OrderSummary orderAlias = null;
query.SelectList(list => list
.Select(o => o.Id).WithAlias(() => orderAlias.Id)
.Select(() => statusAlias).WithAlias(() => orderAlias.Status)
).TransformUsing(Transformer.AliasToBean<OrderSummary>());
-------------------------------- ANSWER ----------------------------------
As I said in my last edit, the problem does not seem to be the actual selection of OrderStatus but returning it to the client. So I thought it was my lack of knowledge of NHibernate instead it was as simple as adding the [JsonObject] attribute to the OrderStatus class. How silly of me.
I have changed my query to the following:
Order orderAlias = null;
OrderSummary orderSummary = null;
OrderStatus statusAlias = null;
var query = session.QueryOver<Order>(() => orderAlias)
.JoinAlias(() => orderAlias.Status, () => statusAlias, JoinType.LeftOuterJoin);
query = query
.Select(
Projections.ProjectionList()
.Add(Projections.Property(() => orderAlias.Id).WithAlias(() => orderSummary.Id))
.Add(Projections.Property(() => orderAlias.Status).WithAlias(() => orderSummary.Status)
);
Result = query.TransformUsing(Tranformers.AliasToBean<OrderSummary>())
.List<OrderSummary>()
.ToList();
I'm afraid that currently it's not possible. I guess that Nhibernate transformers are not able to construct nested complex properties.
You can return list of tuples and then cast it manually to your entity:
OrderStatus statusAlias = null;
var tuples = Session.QueryOver<Order>()
.JoinQueryOver(x => x.Status, () => statusAlias)
.SelectList(list => list
.Select(x => x.Id)
.Select(x => statusAlias.Id)
.Select(x => statusAlias.Name))
.List<object[]>();
var result = tuples.Select(Convert);
private OrderSummary Convert(object[] item) {
return new OrderSummary
{
Id = (long)item[0],
OrderStatus = new OrderStatus { Id = (long)item[1], Name = (string)item[2] }
};
}
Also if you don't bother about performance much it's possible to fetch a list of you Orders and convert it to OrderSummary. You can do it by simply define casting operator or using some tool like AutoMapper or ExpressMapper.
Sorry I didn't see your comment asking for an example before.
I'm going to leave some code explaining the approach I mentioned, although it was already given as an alternative in the other response and I believe it's the easiest way to go (not using transformers at all):
string GetOrderSummaries()
{
// First, you just query the orders and eager fetch the status.
// The eager fetch is just to avoid a Select N+1 when traversing the returned list.
// With that, we make sure we will execute only one query (it will be a join).
var query = session.QueryOver<Order>()
.Fetch(o => o.Status).Eager;
// This executes your query and creates a list of orders.
var orders = query.List();
// We map these orders to DTOs, here I'm doing it manually.
// Ideally, have one DTO for Order (OrderSummary) and one for OrderStatus (OrderSummaryStatus).
// As mentioned by the other commenter, you can use (for example) AutoMapper to take care of this for you:
var orderSummaries = orders.Select(order => new OrderSummary
{
Id = order.Id,
Status = new OrderSummaryStatus
{
Id = order.Status.Id,
Name = order.Status.Name
}
}).ToList();
// Yes, it is true that this implied that we not only materialized the entities, but then went over the list a second time.
// In most cases I bet this performance implication is negligible (I imagine serializing to Json will possibly be slower than that).
// And code is more terse and possibly more resilient.
// We serialize the DTOs to Json with, for example, Json.NET
var orderSummariesJson = JsonConvert.SerializeObject(orderSummaries);
return orderSummariesJson;
}
Useful links:
AutoMapper: http://automapper.org/
Json.NET: http://www.newtonsoft.com/json

LINQ to Entities. How to create "Reusable" methods that "wrap" entities?

SETUP
I have an "Order" class and an "OrderDetail" class.
The Order class has a property called "OrderDetails" of type IQueryable.
I have a method in each class called "GetData" and this method returns IQueryable of the class it is in.
The "GetData" methods are wrappers around the Entities that are used to transform the Entities into friendlier .NET classes / properties.
For example: The OrderDetail Entity has a "PullDate" in the database as Char(10) but I want the OrderDetail Class to have a property called "PullDate" that is of type DateTime in the class.
CODE
public class Order
{
[Key]
public int ID { get; set; }
public IQueryable<OrderDetail> OrderDetails { get; set; }
public static IQueryable<Order> GetData()
{
IQueryable<Order> orders;
var db = new OrderEntities();
// NOTE: This code will work
try
{
var data =
(from O in db.Orders
where O.OrderID == 1
select new Order
{
ID = O.OrderID,
OrderDetails =
(from OD in db.OrderDetails
where OD.OrderID == O.OrderID
select new OrderDetail
{
ID = OD.OrderDetailID,
OrderID = OD.OrderID,
PullDate = OD.PullDate == "00000000" ?
(DateTime?)null : db.yyyyMMddToDate(OD.PullDate),
Description = OD.Desc
})
});
orders = data.AsQueryable();
var orderList = orders.ToList();
}
catch (Exception ex)
{
throw;
}
// NOTE: This code will NOT work
try
{
var data = (from O in db.Orders
where O.OrderID == 1
select new Order
{
ID = O.OrderID,
OrderDetails = (from OD in OrderDetail.GetData(db)
where OD.OrderID == O.OrderID
select OD)
});
orders = data.AsQueryable();
var orderList = orders.ToList();
}
catch (Exception ex)
{
throw;
}
return orders;
}
}
public class OrderDetail
{
[Key]
public int ID { get; set; }
public int OrderID { get; set; }
public DateTime? PullDate { get; set; }
public string Description { get; set; }
public static IQueryable<OrderDetail> GetData(OrderEntities db)
{
IQueryable<OrderDetail> orderDetails;
var data = (from OD in db.OrderDetails
select new OrderDetail
{
ID = OD.OrderDetailID,
OrderID = OD.OrderID,
PullDate = OD.PullDate == "00000000" ?
(DateTime?)null : db.yyyyMMddToDate(OD.PullDate),
Description = OD.Desc
});
orderDetails = data.AsQueryable();
var orderList = orderDetails.ToList();
return orderDetails;
}
}
ERROR
LINQ to Entities does not recognize the method 'System.Linq.IQueryable`1[Models.OrderDetail] GetData(Models.OrderEntities)' method, and this method cannot be translated into a store expression.
Request
I would like the Order.GetData method to call the OrderDetail.GetData method using LINQ.
I need to "join" the GetData methods together or "sub select" the OrderDetail.GetData while inside the Order.GetData class.
Both of the classes are querying EntityFramework inside of their GetData methods.
Projection is a requirement.
My goal is to create "Reusable" methods like "GetData" in my DTO classes that will contain specific SQL / Entity logic.
For example, I am using a lot of custom SQL functions like "db.yyyyMMddToDate" in my DTO classes to transform the Entities into something more object / .NET friendly and I don't want to "retype" all that logic each time I need to "join / sub select" data from entities.
In LINQ to Objects this would be the same as joining two different lists from different classes.
But it seems that LINQ to Entity does not know how to join methods from other classes even if the method is marked as Queryable.
I understand that LINQ to Entity is treating the "GetData" methods as if they were SQL functions but I need a way to tell LINQ to Entity that these are just more Entities to join together to get the results.
You get this error because, when dealing with LINQ to Entities, you are not passing in lambdas to the LINQ operators like you do in LINQ to Object. You are passing expression trees. The code that you write in those queries will never be executed. It will be interpreted by Entity Framework as a series of instruction to translate into an other language like SQL.
The GetData method doesn't mean anything in SQL. In fact, it doesn't mean anything outside of your own program. This is why LINQ to Entities do not recognize your method as a valid construct.
To access the details of an order in a scenario like yours, you need to build your query so that EF knows to include the OrderDetails entities inside the primary query using the Include operator. When doing this, EF expects your object to have a property similar to this one:
public virtual ICollection<OrderDetail> OrderDetails { get; set; }
This is how EF will know where to put the resulting objects from queries that includes those elements.
var ctx = new DatabaseContext();
var query = ctx.Orders
.Where(o => o.OrderId == 1)
.Include(o => o.OrderDetails);
This query will asks the remote server for all Orders, with an OrderId of 1, with all its matching OrderDetails. EF will then automatically create all of the related client side entities for you.
Here's the official documentation on EF about this topic: http://msdn.microsoft.com/en-ca/data/jj574232.aspx

Populating a DTO class List<> with ENtity Framework query

Is It possible to populate a List from within a EF query? My DTO is as follows:
public DTO()
{
public string ClientName { get; set;}
public List<string> RelatedCodes { get; set;}
}
My method to populate DTO =
Public DTO MyResult(string ClientCode)
{
return (from o in repository.RelatedClient
where o.LeadCode == ClientCode
select new DTO { ClientName = o.ClientName, RelatedCodes = o.RelatedCodes.ToList()});
}
I know I shouldn't be adding the ToList() within the query or if I can I am doing it very wrong. Can anyone advise how this is done. My DTO is cut down for this example but I want to have lots of single properties and a List<> (or several Lists) in a DTO with one Entity query if possible?
So following answer below I presume there isnt a way to query this direct. My original option would have been:
Public DTO MyResult(string ClientCode)
{
var temp = (from o in repositry.RelatedCode Where o.LeadCode == ClientCode select o).ToList();
DTO dto = (from o in repository.LeadClient Where o.LeadCode == ClientCode Select o.ClientName).Firstordefault();
foreach(string rc in temp)
{ dto.RelatedCode.Add(rc);}
return dto;
}
I am happy with this but would be grateful if someone could advise if this is the correct way to deal without something like automapper. I am trying to learn Entity Framework and want to check I am not missing some built in functionality.
Something like:
var dtoEntity = repo.RelatedClient.SingleOrDefault(x => x.LeadCode == ClodeCode);
DTO d = new DTO();
d.ClientName = dtoEntity.ClientName;
foreach (var relatedCode in dtoEntity.RelatedCodes)
{
d.RelatedCodes.Add(relatedCode);
}
return d;
Using this approach you can add as many properties as you'd like. However, I'd suggest using AutoMapper for this.
Read more here:
http://nuget.org/packages/automapper

Categories

Resources