I am new to Entity Framework and Linq, I would like to understand how dbset/dbcontext works when executing the following kind of LINQ request:
from x in db.Products select x
db is the data context object, Products the dataset.
Is the search/loading of these records done directly at the base table level or is a first search done on the dbset? And then we complete and retrieve the records that are not yet tracked/in the dbset?
In other words what is the path of the loading of these elements?
Thank you,
Is the search/loading of these records done directly at the base table level or is a first search done on the dbset?
It's done so at the "base table level" in the Database Server by receiving the results directly from the query and then DataContext will return any existing entity that it already have track of and create new entities if it doesn't have any track for those records.
And then we complete and retrieve the records that are not yet tracked/in the dbset?
The DataContext will create new entities for those records and it'll be tracked if you didn't explicitly specify AsNoTracking.
In other words what is the path of the loading of these elements?
The way it works from this document is that when you make a LINQ Query like this:
from x in db.Products select x
It will generates a LINQ Expression and then pass that expression to the Database Provider to generate the actual database query specific to the database engine it's made for (it may not have all of the query compiled, so some of the query may be computed from the application side.)
It will then execute the query and receive the result from that query and if the query is made with tracking, then it'll return any existing entity that the DataContext already have track of and create new entities if not.
The entity and record will be tied by the key and whenever there is any part of the query using Keyless Entity Type, the whole query would be made as a NoTracking query.
Note that if the database record for such existing entity have changed, it will not update the values in the existing entity, you will have to manually reload that entity like so:
db.Entry(product).ReloadAsync();
Related
I am using Entity Framework 6.1.3 to generated the entities and data model.
If I have two tables: Orders -> OrderDetails, with a relation between them (OrderId), then I can get all the orders and related OrderDetails with the following query
dbContext.Order().Include(a => a.OrderDetails);
But if I created a view (vOrder) for Orders, then there is no direct relation between vOrder and OrderDetails in the model, though I can link them together with joins on OrderId. How could I still get all the data from vOrder and related OrderDetails. The following query doesn't work unless I add all the navigation properties manually.
dbContext.vOrder().Include(a => a.OrderDetails);
Is there a simple LINQ query to accomplish the intended query?
Thanks for your help.
Do a manual join and return an anonymous object that contains both.
Something like:
dbContext.vOrder
.GroupJoin(
dbContext.OrderDetails,
v=>v.orderid,
od=>o.orderid,
(v,od)=>new {v=v,od=od});
Of course, you could just add the appropriate naviation properties on to vOrder and do exactly what you said.
Why not just include more columns in the view (or create another view that has all the required data, if you don't want to modify the first one)?
I'm new to LINQ and the Entity Framework. I've been fetching collections from the database using the following:
var Publications = from pubs in db.RecurringPublications
select pubs;
The Publications table is linked to other tables via foreign keys. I've been using this to reference properties like this:
Publications.Single().LinkedTable.LinkedTableColumn
and sometimes even further down the chain:
Publications.Single().LinkedTable.LinkedTable.LinkedLinkedTableColumn
I know you can specify lazy loading or eager loading, I was wondering how it's handled by default. Is there a maximum depth by default? Does it figure out how many joins to use at compile time?
It's only going to eager load what's in that specific table.
var Publications = from pubs in db.RecurringPublications
select pubs;
Will only get the data from your RecurringPublications table. You can specify if you want to load additional properties, but if you don't specify anything, it will only give you exactly what you ask for - nothing more.
Publications.Single().LinkedTable.LinkedTableColumn
Is lazy loading your LinkedTableColumn - now if your return is Queryable (and it is so far), it's going to do a join and return a single SQL query.
However, if the call has already been enumerated, it will make a second call.
Blog post to MSDN for info
I'm using Entity Framework but I've cached some application wide entities, so now they're List rather than entities.
Two of the objects I've cached are Products and Stores - a Product has a store. In a table they are linked by StoreId, but since I'm using EF the Product can also include the Store entity.
I don't cache them together simply because they are also used independently. What I would like to do is join them at some point, so I might subselect the Product object then want to populate Stores by joining the Stores object.
Is the most efficient way of joining 2 lists using linq - if so whats the most efficient syntax, or is there's a better way converting lists back to entities.
is there a better way of converting lists back to entities
This is a bit misleading as this isn't what your trying to do. You pull down a list of Products/Stores which are entities - no need to convert them (even if your storing them in a list).
If I understand you correctly what you want to do is basically map each Product to it's appropriate Store from the cached entities (to save going back to the DB by accessing the Store property on the Product entity). I am pretty sure all you need to do is map this across, so something like:
foreach (var product in cachedProducts)
{
product.Store = cachedStores.SingleOrDefault(s => s.Id == product.StoreId);
}
Your entities are connected via the underlying database context, so removing them from this context prevents you from joining them back later or even saving them without attaching context.
the most efficient design is to use EF's IQueryable syntax to retrieve them whenever you need them and let the database context do any caching required / possible.
With EF I can return a collection of objects like so
entities.Customers.ToArray();
And I can include other tables, so I can effectively get 2 result sets back in the one query
entities.Customers.Include("Invoice").ToArray();
or if I have some custom SQL I can achive a similar result:
SqlDataReader reader = GetReaderFromSomewhere("SELECT * FROM Customer");
entities.Translate<Customer>(reader).ToArray();
But how do I get multiple results back from my own SQL? What I was thinking was something like this
SqlDataReader reader = GetReaderFromSomewhere("SELECT Customer.Name AS CustomerName, Invoice.Number AS InvoiceNumber FROM Customer JOIN Invoice ON Customer.ID = Invoice.CustomerID");
entities.Translate<Customer>(reader).Include<Invoice>().ToArray();
In the above example I have prefixed all the returned data with the table name so that the Translate method can know which columns belong to which tables. I'm presuming the Tranlate method does not support this but EF must do something similar when the include method is called. So my question is, how can I get the functionality of Include when using Translate?
AFAIK you can not do that manually. What EF does is, it dynamically generate a class based on the LINQ query(and the Includes) that can materialize entities. Basically this class knows which columns will be mapped to which properties.
However you can use a micro ORM like Dapper which can do Multi Mapping. But this will only work for querying. So change tracking and CUD operations will not be available.
I have a standard self referencing table of Categories. In my entity model I have made associations Children and Parent. Is it possible to load the whole Category object without lazy loading?
if I use the code below, it loads only to the second level.
db.Categories.MergeOption = System.Data.Objects.MergeOption.NoTracking;
var query = from c in db.Categories.Include("Children")
where c.IsVisible == true
orderby c.SortOrder, c.Id
select c;
Is it possible to load references if I have all the category objects already loaded?
One method to load it is to add the Children property multiple times
db.Categories.Include("Children.Children.Children.Children.Children")
but this generates a very long insane T-SQL code and also it doesn't do what I want.
No, it isn't possible. Consider: All LINQ to Entities queries are translated into SQL. Which SQL statement includes an unlimited depth in a self-referencing hierarchy? In standard SQL, there isn't one. If there's an extension for this in T-SQL, I don't know what it is, and I don't think EF providers do, either.
Ok, you might consider using Load method.
if (!category.Children.IsLoaded)
category.Children.Load();
Of course, category entity need to be tracked by ObjectContext.
There is better explanation here how-does-entity-framework-work-with-recursive-hierarchies-include-seems-not-to.
One way I have used to implement that if I have several entities I want to get all children in self-referencing table is to use recursive cte and stored procedure to get their ids using Entity FrameWork :
Here is the code using Entity Framework and code first approach