I'm trying to upgrade a large application which uses Entity Framework 4 to use Entity Framework 5.
I've discovered a function like this:
public FooModel(FooEntity foo)
{
_foo = foo;
_foo.bars.Load(System.Data.Objects.MergeOption.OverwriteChanges);
}
Where foo and bar are generated entities, with bar having a foreign key to foo.
It seems EF5 no longer has the .Load(MergeOption) function, and I've never seen it before.
Does anyone know what it does, and what its equivalent is?
https://stackoverflow.com/a/13178313/784908 suggests that Load is part of DbContext - but my entity container inherits from DbContext, and still isn't available
My best guess is that it is used for Eager loading of the foreign keys (which I need to do, the context is created and disposed of many times in a request, and there is no guarentee it will exist/attached when FooModel is used)
Entity Framework - eager loading of related entities shows I should be using .Include(), but that function doesn't seem to be available on an actual entity (I think the term is 'materialized query'?)
Thanks for reading
.Load() loads an IQueryable query from database into the memory - in fact, Local property of the relevant entity of your DbContext.
You can use this method with any IQueryable collection, not just the DbContext. Examples are as the following:
var q = db.Products.Include("Category").ToList();
q.Load(); // -> you can't!
// ------------
db.Products.Include("Category").Load(); // It's OK!
// This will NOT query the database, just looks in-memory data.
var p = db.Products.Local.Single(id);
// ------------
var q = db.Products.Include("Category").ToList();
q.AsQueryable().Load(); // -> It's OK!
// This also will NOT query the database, just looks in-memory data.
var p = db.Products.Local.Single(id);
The load function is mainly used for 2 reasons:
1) Retrieving some parts of data from Db to memory and work with them:
db.Products.Include("Category").Where(p => p.CatId == 10).Load();
2) To be able to use Linq-to-Objects methods which L2E doesn't supports(like .ToString(), etc.) - as the Local property of DbContext entities are ObservableCollection<T> which implements IEnumerable, just as L2O objects:
db.Products.Include("Category").Where(p => p.CatId == 10).Load();
string subName = db.Products.Local.Find(id).SubString(0, 4);
Related
I am maintaining an application which uses EF Core to persist data to a SQL database.
I am trying to implement a new feature which requires me to retrieve an object from the database (Lets pretend its an order) manipulate it and some of the order lines which are attached to it and save it back into the database. Which wouldn't be a problem but I have inherited some of this code so need to try to stick to the existing way of doing things.
The basic process for data access is :
UI -> API -> Service -> Repository -> DataContext
The methods in the repo follow this pattern (Though I have simplified it for the purposes of this question)
public Order GetOrder(int id)
{
return _context.Orders.Include(o=>o.OrderLines).FirstOrDefault(x=>x.Id == id);
}
The service is where business logic and mapping to DTOs are applied, this is what the GetOrder method would look like :
public OrderDTO GetOrder(int id)
{
var ord = _repo.GetOrder(id);
return _mapper.Map<OrderDto>(ord);
}
So to retrieve and manipulate an order my code would look something like this
public void ManipulateAnOrder()
{
// Get the order DTO from the service
var order = _service.GetOrder(3);
// Manipulate the order
order.UpdatedBy = "Daneel Olivaw";
order.OrderLines.ForEach(ol=>ol.UpdatedBy = "Daneel Olivaw");
_service.SaveOrder(order);
}
And the method in the service which allows this to be saved back to the DB would look something like this:
public void SaveOrder(OrderDTO order)
{
// Get the original item from the database
var original = _repo.GetOrder(order.Id);
// Merge the original and the new DTO together
_mapper.Map(order, original);
_repo.Save(original);
}
Finally the repositories save method looks like this
public void Save(Order order){
_context.Update(order)
_context.SaveChanges();
}
The problem that I am encountering is using this method of mapping the Entities from the context into DTOs and back again causes the nested objects (in this instance the OrderLines) to be changed (or recreated) by AutoMapper in such a way that EF no longer recognises them as being the entities that it has just given to us.
This results in errors when updating along the lines of
InvalidOperationException the instance of ProductLine cannot be tracked because another instance with the same key value for {'Id'} is already being tracked.
Now to me, its not that there is ANOTHER instance of the object being tracked, its the same one, but I understand that the mapping process has broken that link and EF can no longer determine that they are the same object.
So, I have been looking for ways to rectify this, There are two ways that have jumped out at me as being promising,
the answer mentioned here EF & Automapper. Update nested collections
Automapper.Collection
Automapper.collection seems to be the better route, but I cant find a good working example of it in use, and the implementation that I have done doesn't seem to work.
So, I'm looking for advice from anyone who has either used automapper collections before successfully or anyone that has any suggestions as to how best to approach this.
Edit, I have knocked up a quick console app as an example, Note that when I say quick I mean... Horrible there is no DI or anything like that, I have done away with the repositories and services to keep it simple.
I have also left in a commented out mapper profile which does work, but isn't ideal.. You will see what I mean when you look at it.
Repo is here https://github.com/DavidDBD/AutomapperExample
Ok, after examining every scenario and counting on the fact that i did what you're trying to do in my previous project and it worked out of the box.
Updating your EntityFramework Core nuget packages to the latest stable version (3.1.8) solved the issue without modifying your code.
AutoMapper in fact "has broken that link" and the mapped entities you are trying to save are a set of new objects, not previously tracked by your DbContext. If the mapped entities were the same objects, you wouldn't have get this error.
In fact, it has nothing to do with AutoMapper and the mapping process, but how the DbContext is being used and how the entity states are being managed.
In your ManipulateAnOrder method after getting the mapped entities -
var order = _service.GetOrder(3);
your DbContext instance is still alive and at the repository layer it is tracking the entities you just retrieved, while you are modifying the mapped entities -
order.UpdatedBy = "Daneel Olivaw";
order.OrderLines.ForEach(ol=>ol.UpdatedBy = "Daneel Olivaw");
Then, when you are trying to save the modified entities -
_service.SaveOrder(order);
this mapped entities reach the repository layer and DbContext tries to add them to its tracking list, but finds that it already has entities of same type with same Ids in the list (the previously fetched ones). EF can track only one instance of a specific type with a specific key. Hence, the complaining message.
One way to solve this, is when fetching the Order, tell EF not to track it, like at your repository layer -
public Order GetOrder(int id, bool tracking = true) // optional parameter
{
if(!tracking)
{
return _context.Orders.Include(o=>o.OrderLines).AsNoTracking().FirstOrDefault(x=>x.Id == id);
}
return _context.Orders.Include(o=>o.OrderLines).FirstOrDefault(x=>x.Id == id);
}
(or you can add a separate method for handling NoTracking calls) and then at your Service layer -
var order = _repo.GetOrder(id, false); // for this operation tracking is false
Assuming that I have an entity with virtual nagivation property like this:
public class School
{
public long Id { get; set; }
public virtual ICollection<Students> Students { get; set; }
}
As I understand, EF6 uses proxy to enable lazy-loading of Students, but do the following LINQ queries:
var myStudent = this.Students.Single(x => x.Id == id);
var studentsCount = this.Students.Count();
var bestStudents = this.Students
.OrderByDescending(x => x.GPA)
.Take(5)
.ToArray();
result into a SQL query (just like IQueryable<T> does)? Or is it just a lazy-loading collection and will load all students into memory after the first request, and then perform simple IEnumerable<T> LINQ behaviour?
When you query for an entity in Entity Framework, the objects that get returned are not (always) the type of object you think they are. Behind the scenes, it creates a brand new class that inherits from the your class. Because OOP allows a subclass to be stored in a variable typed as the superclass, you never really notice. This is the "proxy" that you mention. That's why the virtual function allows lazy loading. The subclass overrides your virtual method, and contains the code to lazy load the extra data before returning it.
That overridden property call will then check the context to see if the navigation properties are already loaded. If they are, it just returns them. If they are not, it will make additional SQL calls to load them, storing them in the DbContext for later.
In your updated question, my understanding is that running those lines of code would result in 3 separate queries being executed.
Public virtual properties are lazy loading in EF6.
You can disable lazy loading for a DbContext, or use the .Include() method on the IQueryable to include the property in the first query.
http://www.entityframeworktutorial.net/EntityFramework4.3/lazy-loading-with-dbcontext.aspx
https://msdn.microsoft.com/en-us/library/jj574232(v=vs.113).aspx
Once you "iterate" through the list (e.g. by calling the .Single(), .Count() or .ToArray() method), the query is executed and you have a in-memory list of your students. See https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/ef/language-reference/query-execution for more details about query execution.
The first example would result in 3 queries, where the first returns the student with the given Id, the second returns the student count and the third returns the first 5 students ordered desc by their GPA property.
Regarding DDD => You can use some Layered architecture, with ApplicationServices and DomainServices, where DomainServices perform the domain logic and ApplicationServices load / transform the data.
The https://aspnetboilerplate.com/ template is for example a good starting point for domain driven design.
Assuming that the second code block is executed somewhere INSIDE the scope of an instance of 'School' (so 'this' is an instance of 'School' - in my example below school19) then the following scenarios are possible:
A) You have loaded your instance of 'School' like this (Lazy loading enabled):
var school19 = dbContext.Set<School>()
.FirstOrDefault(school => school.Id == 19)
Then your 3 lines of code for accessing the property 'Students' will trigger a single additional database hit when
var myStudent = this.Students.Single(x => x.Id == id);
is executed, but no more database hits will occur with the subsequent two statements.
B) In case you have loaded your instance of 'School' like this (Lazy loading enabled):
var school19 = dbContext.Set<School>()
.Include(school => school.Students)
.FirstOrDefault(school => school.Id == 19)
Then your 3 lines of code for accessing the property 'Students' will not trigger an additional database hit.
C) If lazy loading was disabled, then
A) would result in a Null Reference Exception
B) would behave the same
As a last remark, if 'this' was a reference to an instance of the DBContext class, which has a property
public Set<School> Schools { get; set; }
then it would trigger 3 different database calls. But the result is different as this would be executed in the context of ALL schools, while my assumptions above only apply to a single school.
This is a question for Automapper professionals. I have tried to do query mapping for several days already - and no luck. Seems like Automapper is not intended to be used the way I want to use it. But maybe I am wrong. So here is the question...
I have such classes:
CatDto (Name, Age, Toys (collection of ToyDto objects))
ToyDto (CatName, ToyName, Cat (parent CatDto object))
Cat (comes from Entity Framework, has properties similar to those in CatDto)
Toy (comes from Entity Framework, has properties similar to those in ToyDto)
I want to write a generic read function in my data access layer, something like this:
IEnumerable<CatDto> Read(IQueryable<CatDto> query) {
// here "query" is converted
// to Entity Framework query by means of AutoMapper,
// EF query gets executed,
// I convert EF entities (Cat) back to CatDto - this is not essential
// result is returned
}
I will call this function in different manners. Example:
var q = new ObjectModel.Collection(Of CatDto)).AsQueryable();
q = q.Where(c => c.Toys.Count() > 1);
var someResultVar = Read(q);
So far any attempts to implement such behavior have failed. I wonder if Automapper is a helper here or am I going completely wrong way?
I believe the functionality you want is in UseAsDataSource
You can't map IQueryable, but you shouldn't need to with UseAsDataSource
Example
IQueryable<CatDto> someResultVar = new ObjectModel.Collection(Of CatDto)).AsQueryable().UseAsDataSource().For(Of OrderLineDTO).Where(c => c.Toys.Count() > 1);
When you enumerate it will convert Lambda from CatDto to CatEf and call ProjectTo<CatDto> and return CatDto objects
I'm using Entity Framework 5 with ObjectContext on a relatively big and complex data model.
I would like to work around big queries generated when chaining multiple IQueryable.Include(Path) to eager load related objects.
For example, I'm doing something like this :
var queryPe = context.Person.Where(p => p.Id == 110).Include(#"AA");
queryPe = queryPe.Include(#"BB.CC.DD");
queryPe = queryPe.Include(#"EE.FF");
It could be made generic by using a string array and chaining each graph at runtime in a foreach loop.
Instead, I would like to do something like this :
Person pe = context.Person.Where(p => p.Id == 110).First();
context.LoadProperty(pe, "AA");
pe.BB.Attach(pe.BB.CreateSourceQuery().Include(#"CC.DD"));
pe.EE.Attach(pe.EE.CreateSourceQuery().Include(#"FF"));
Instead of having one big query we would have 4 smaller queries hitting the database.
Of course I still want to leverage the power of the graph path as a string.
I may be wrong, but this means that I should use relexion to get the navigation properties by name and executing the CreateSourceQuery() on it because there is no such extension method to do this.
Am I correct ?
EDIT 1 : Well, I have an additionnal constraint, that is, I'm using Self Tracking Entities (STE). This means that Related objects are not materialized as EntityCollection or EntityReference. So Attach() and CreateSourceQuery() are not available !
So I'm stuck with Context.LoadProperty to deal with object graphs.
Is it only possible ?
EDIT 2 : Problem exposed in EDIT 1 solved, thanks to the help of DbContext class. See the code below :
Person pe = context.Person.Where(p => p.Id == 110).First();
context.LoadProperty(pe, "AA");
DbContext dbc = new DbContext(context, false);
dbc.Entry(pe).Collection(#"BB").Query().Include(#"CC.DD").Load();
dbc.Entry(pe).Reference(#"EE").Query().Include(#"FF").Load();
EDIT 3 02/11/2013 : There is an issue with the code presented above (EDIT 2). If the last entity in the path is a reference and not a collection, the code doesn't fail but it is not loaded :-(
EDIT 4 : Instead of using reflection, right now, I'm generating the code by looking at the Entity Data Model with the help of a T4 template.
Sometimes stored procedures are best. Write a stored procedure that returns multiple result sets, one for each type of entity you wish to eagerly load. This is highly performant compared to what you're trying to accomplish and the stored procedure will be far more readable than this jumble of includes and separate load statements per reference/collection. And yes, EF will hook up related entities automatically!
Here's a reference for sprocs with multiple result sets for both EDMX and code first:
http://msdn.microsoft.com/en-us/data/jj691402.aspx
Try to separate your aggregates in multiple contexts. Each Bounded context should have a separate context. This way you create a loosely coupled entity framework solution.
Julie Lerman has a good video on plural sight about this concept.
I would prefer to use stored procedures. Easy maintainance, works faster etc.
I'm new to Entity Framework. I've created a Multi Tier Application, in MVC, using Ninject.
I have three tables in the database. Say Table A, Table B and Table C.
Table A has a foreign key relating it to Table B
Table B has a foreign key relating it to Table C
Table A => Table B => Table C
My Application has a "service" which will be called from an MVC Controller.
The service acts as a repository for every entity (ie TableAService, TableBService), which is responsible for Creating, Reading, Updating or Deleting Entities from the EF DataContext, aswell as possibly performing business logic on those entities.
Within my MVC controller I have a reference to the appropriate service. For example:
private TableAService _tableAService;
public TableAController(EFDataContext dataContext)
{
_tableAService = new TableAService(dataContext);
}
public ActionResult Index()
{
return View();
}
TableAService would look something like this:
private EFDataContext _dataContext;
public TableAService(EFDataContext dataContext)
{
_dataContext = dataContext;
}
public TableA GetById(int tableAId)
{
_dataContext.TableA.SingleOrDefault(ta => ta.TableAId == tableAId);
}
I appreciate that the example's service would be tightly coupled to the dataSource, my actual implementation differs slightly but the concept is the same, I have a service with a dataContext that I'd like to return entities from.
QUESTION : - When I'm in the GetById method in the TableAService, SingleOrDefault gives me a TableB navigation property, which allows me to access all TableB's properties, including a TableC navigation property.
However, when I pass TableA back to the Controller, I can't access any of TableB's properties.
Within the Service I've also tried:
private ObjectSet<TableA> _objSet = _dataContext.CreateObjectSet<TableA>();
and
return _objSet.SingleOrDefault(ta => ta.TableAId == tableAId);
This doesn't seem to make any difference to being able to Access the TableC navigation property on TableB from the TableA entity.
Any help would be greatly appreciated!
Cheers,
James
The contents of a navigation property can only be loaded within the scope of an active ObjectContext.
This is required because the actual rows will be fetched through a round-trip to the database.
In your case your are trying to access a navigation property after the ObjectContext that was used to retrieve the entities in the first place has been disposed and the connection lost.
Assuming you're using Entity Framework 4 there are 2 solutions to this problem:
Eager loading: the related entities are loaded up front, that is you explicitly instruct Entity Framework to load all related entities while it's retrieving the results of the query. This can be done in a couple of different ways: by including the related entities in the query's projection, by invoking the ObjectQuery.Include method or by invoking the Load method on the navigation property, alternatively the ObjectContext.LoadProperty method.
Lazy loading: the related entities are loaded on-demand, that is when the navigation property's getter is accessed for the first time. Note that this must still be done within the scope of an ObjectContext.
In your case eager loading using the Include method is probably the most appropriate solution:
public TableA GetById(int tableAId)
{
return _dataContext.TableA
.Include("TableB.TableC") // use dot-notation to specify depth in the object graph
.SingleOrDefault(ta => ta.TableAId == tableAId);
}
Related resources:
Loading Related Objects
Navigation Properties
Try changing your GetById method to:
public TableA GetById(int tableAId)
{
return _dataContext.TableA.Include("TableB").SingleOrDefault(ta => ta.TableAId == tableAId);
}
If you want to get the TableC record as well, use:
public TableA GetById(int tableAId)
{
return _dataContext.TableA.Include("TableB.TableC").SingleOrDefault(ta => ta.TableAId == tableAId);
}
The reason is that Entity Framework uses "lazy loading", which means that stuff isn't loaded from the database until you really need it. The trouble is, once you're out of the service, the data context doesn't exist any more to get the table B record. The Include method instructs EF to load the data from related tables straight away.
It's took some digging, but the problem I was experiencing was that my application wasn't referencing System.Data.Entity.
Adding the reference to the application allowed me to access the properties of the related objects from within the controller.
Thanks for your answers guys, they did help me rule out possibilities. I up voted each.