entity framework load only parent entity - c#

I need to load an entity from Entity Framework(EF) but I only need the entity itself, I don't need any childs. I'm having troubles sending an object trought sockets because of the weight of the object.(Any suggestion about this?)
I'm using this code to get the list of objects I need:
…
private static DBEntities context = new DBEntities();
listaPlatos = context.PLATO.ToList();
…
My problem is that each object "PLATO" has others objects as childs. I want to ignore that childs and get only the "PLATO" entity.
Thanks.

Since you don't use an explicit loading of children, I guess lazy loading may cause you problems.
Check out
context.Configuration.LazyLoadingEnabled = false;
Here is a relevant link:
http://msdn.microsoft.com/en-us/data/jj574232.aspx

I think the problem is the serializer. A solution could be to use another class which is a pure POCO DTO class (this is always a best practise when you serializing something over the wire (sockets, WCF, whatever)).
var listaPlatos = context.PLATO.Select(x => new PlatoDto {
Prop1 = x.SomeProp
});

Related

Duplicating a model that has a hierarchy

My model looks something like this:
Company
-Locations
Locations
-Stores
Stores
-Products
So I want to make a copy of a Company, and all of its associations should also be copied and saved to the database.
How can I do this if I have the Company loaded in memory?
Company company = DbContext.Companies.Find(123);
If it is tricky, I can loop through each association and then call create a new object. The Id's will be different but everything else should be the same.
I am using EF 6.
Cloning object graphs with EF is a piece of cake:
var company = DbContext.Companies.AsNoTracking()
.Include(c => c.Locations
.Select(l => l.Stores
.Select(s => s.Products)))
.Where(c => c.Id == 123)
.FirstOrDefault();
DbContext.Companies.Add(company);
DbContext.SaveChanges();
A few things to note here.
AsNoTracking() is vital, because the objects you add to the context shouldn't be tracked already.
Now if you Add() the company, all entities in its object graph will be marked as Added as well.
I assume that the database generates new primary key values (identity columns). If so, EF will ignore the current values from the existing objects in the database. If not, you'll have to traverse the object graph and assign new values yourself.
One caveat: this only works well if the associations are 1:0..n. If there is a n:m association, identical entities may get inserted multiple times. If, for example, Store-Product is n:m and product A occurs at store 1 and store 2, product A will be inserted twice. If you want to prevent this, you should fetch the objects by one context, with tracking (i.e. without AsNoTracking), and Add() them in a new context. By enabling tracking, EF keeps track of identical entities and won't duplicate them. In this case, proxy creation should be disabled, otherwise the entities keep a reference to the context they came from.
More details here: Merge identical databases into one
I would add a method to each model that needs to be cloneable this way, I'd recommend an interface for it also.
It could be done something like this:
//Company.cs
Company DeepClone()
{
Company clone = new Company();
clone.Name = this.name;
//...more properties (be careful when copying reference types)
clone.Locations = new List<Location>(this.Locations.Select(l => l.DeepClone()));
return clone;
}
You should repeat this basic pattern for every class and "child" class that needs to be copiable. This way each object is aware of how to create a deep clone of its self, and passes responsibility for child objects off to the child class, neatly encapsulating everything.
It could be used this way:
Company copyOfCompany123 = DbContext.Companies.Find(123).DeepClone;
My apologies if there are any errors in the above code; I don't have Visual Studio available at the moment to verify everything, I'm working from memory.
One other really simple and code efficient way to deeply clone an object using serialization can be found in this post How do you do a deep copy an object in .Net (C# specifically)?
public static T DeepClone<T>(T obj)
{
using (var ms = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(ms, obj);
ms.Position = 0;
return (T) formatter.Deserialize(ms);
}
}
Just be aware that this can have some pretty serious resource and performance issues depending on your object structure. Every class that you want to use it on must also be marked with the [Serializable] attribute.

How to serialize into a json from entity?

I'm trying to serialize an (Entity Framework 6) entity into json. I am making sure the entry is in memory before serializing via the AsNoTracking() method however I get an error as it cant receive a value form a different table that is referenced in the entry.
Inner Exception: When an object is returned with a NoTracking merge option, Load can only be called when the EntityCollection or EntityReference does not contain objects.
Exception: JsonSerializationException: Error getting value from 'TABLE_X' on 'System.Data.Entity.DynamicProxies....
Code:
List<Location> locations = new DbContext().Locations.Where(x => x.Type == 1).Take(5).AsNoTracking().ToList();
string s = JsonConvert.SerializeObject(locations, new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
All I want to do is return a string of the serialized entity. Im not worried about other objects, solely the locations entity.
When I tried disposing of the connection and then json serializing I received the error: The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
I only want to serialize my list, I do not want to return/serialize any foreign dependencies.
This an EF's dynamic proxy issue you have to disable it to have your code working
in your class that inherit from DbContext
public class MyModelEntities : DbContext
{
public MyModelEntities()
{
//just disable it like this
Configuration.ProxyCreationEnabled = false;
}
}
Mainly what's happening is that your JsonConvert is trying to serialize an object like this System.Data.Entity.DynamicProxies.Location_5E43C6C196972BF0754973E48C9C941092D86818CD94005E9A759B70BF6E48E6
due to the proxy, which cannot be found because it's dynamically created
You don't need to call AsNoTracking method to load to memory the entities you need. The ToList method is going to do that job.
Now about your issue, is because the JSON serializer is trying to access to each property on an Location instance and you can end up querying for your entire database just because lazy loading is enabled. So, you have two options:
Disable Lazy loading (As #BRAHIMKamel recommended)
Use JsonIgnore atribute over the navigation properties you don't want to be loaded.
Personally, I prefer the first one, and when I need to load a entity with some specific related entity, I use eager loading to load it as part of the query:
context.Locations
.Include(l=>l.State)//eager loading an hypothetical related entity
.Where(x => x.Type == 1)
.Take(5)
.ToList();
If your object graph is not too complicated, different approach could be to create simple POCO class, where your Location will be mapped from. Let's say LocationModel. This could be mapped by hand or for example with AutoMapper.

The ObjectContext instance has been disposed and can no longer be used

I've seen this question asked a million times, but every single suggestion I've encountered I already seem to have covered.
I have entity framework in my MVC solution, and I have a 'repository' which attempts to retrieve a collection of MyObjects:
public static List<MyObject> GetMyObjects()
{
using (var context = new MyEntities())
{
return context.MyObjects.Include("Contact").OrderByDescending(o => o.Date).ToList();
}
}
I call this method as part of a controller action which attempts to serialize it:
public JsonResult All()
{
return Json(MyRepository.GetMyObjects(), JsonRequestBehavior.AllowGet);
}
And I get the following error:
The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
I don't know where to turn on this one, I appreciate entity framework 'lazy-loads' relational data sets if and when they're needed, and I appreciate attempting to serialize the whole collection would indeed attempt to load these (outside of the using statement), but I have the 'Include' there.
What I've Tried
I've tried the 'include', I've also ensured no other associations are part of the MyObject class (i.e. I have no other Include()s to write).
To avoid this you have some options.Don't declare your navigation properties as virtual or disable Lazy Loading behavior on your context. Lazy loading is enable by default and is achieved by creating instances of derived proxy types and then overriding virtual properties to add the loading hook. So, if you want to work with a serializer I recommend you turn off lazy loading:
public class YourContext : DbContext
{
public YourContext()
{
this.Configuration.LazyLoadingEnabled = false;
}
}
These links can help you to understand better what I explain in my answer:
Loading Related Entities
Requirements for Creating POCO Proxies
If you remove the virtual keyword from your navigation properties, the POCO entity not meet the requirements described in the second link, so, EF won't create a proxy class to lazy load your navigation properties. But if you disabled lazy loading, even when your navigation properties are virtual, they won't be loaded in any entity. It's good idea disable lazy loading when you are using a serializer. Most serializers work by accessing each property on an instance of a type.
As a third option you could use the JsonIgnore attribute on your navigation properties that you don't want to be serialized as part of your entity, but as I said before, the best option is disable lazy loading.
When you use Include and using Lazy loading, and wrap the dbContext in a Using statement, then once it tries to get the linked objects, the dbContext is already disposed.
You can try eager loading of the navigation property like this:
IQueryable<MyObjects> query = db.MyObjects.Include(m => m.Contact);
Or you could take out the Using statement, as it is limiting your lazy loading...
I had the same problem and solved like below;
I created a new object and put the values I am gonna use after getting object from db.
Example Code:
var listFromDb= db.XTable.Where(x => x.Id > 5).ToList();
var list = new List<Package>();
foreach (var item in listFromDb)
{
var a = new Package()
{
AccountNo = item.AccountNo,
CreateDate = item.CreateDate,
IsResultCreated = item.IsResultCreated,
};
list.Add(a);
}

Lazy loading not working for POCO classes in Entity Framework

Please help me, I am new to EF.Lazy loading for POCO objects doesn't seem to be working.
My POCO classes are in a sepearte assembly, other than the one one for Data access(i.e DAL)
The Data Acess layer simply wraps the calls made to the EF's object context. Please see the code below
public FilterMaster GetFilter(long ID)
{
FilterMaster entity = new FilterMaster();
try
{
using (var context = new RadarEntities())
{
//context.ContextOptions.LazyLoadingEnabled = false;
//context.ContextOptions.ProxyCreationEnabled = true;
entity = context.FilterMasters.SingleOrDefault(filter => filter.ID == ID);
//context.FilterMasters.Include(
context.LoadProperty(entity, "SQLQuery");
}
}
When DAL call is completed, the ObjectContext is lost, and when I tried to fetch the related child objects of the Root POCO class, I get null.
I've tried explicitly enabling ProxyCreation, EnabledLazyLoading, checked the proxy clases generated are not sealed and all the related properties are marked virtual (as suggested on some other links).
-As the lazy load was not working, I thought of eagerly loading all the related POCO objects, so tried invoking LoadProperty method, which works.
Q1: Am I Imissing something the lazy loading isn't working?
Q2: If I want to expelictly load all the related child objects the will have to call the LoadProperty method for all properties or there is any simpler way?
You are disposing your ObjectContext. This is what is preventing you from using LazyLoading. If you need LazyLoading, the class containing GetFilter should create an ObjectContext when it is created, implement IDisposable, and dispose of the ObjectContext when it is disposed.
Q1: Am I Imissing something the lazy loading isn't working?
It's working but there is no magic involved - underneath a proxy is created for you which will try to retrieve the property value from the database for you on the first access.
For EF the database connection is represented by the context, which you currently dispose automatically at the end of your using block. Without database connection EF cannot lazily retrieve the properties and hence lazy loading won't work.
You will have to keep the context alive until you have accessed all the properties you need to access for lazy loading, or alternatively eagerly load those properties.
Q2: If I want to explicitly load all the related child objects the
will have to call the LoadProperty method for all properties or there
is any simpler way?
Yes, you can specify an Include() query to eagerly retrieve properties, in your case that would be:
entity = context.FilterMasters
.Include("SQLQuery")
.SingleOrDefault(filter => filter.ID == ID);

How would one code an entity instance method to persist itself in Entity Framework 4.0?

I'm working with a small model in Entity Framework 4.0. I'd like to have an instance method of the object that represents an entity persist the entity to the database. So instead of from "external" code:
public static void Main(string[] args)
{
using (EFContext ctx = new EFContext())
{
context.AnEntitySet.AddObject(refToTheEntityInstance);
context.SaveChanges();
Instead, I want the instance of the entity to persist itself, where Contact is the entity name.
public ContactInstance : Contact
{
public void Persist(List<AnotherEntity> otherEntityList)
{
using (EFContext ctx = new EFContext())
{
...
ctx.Contacts.AddObject(this); // DOESN'T WORK.
...
...wire up navigation property to collection of AnotherEntity...
ctx.SaveChanges();
I'm doing something wrong. Is this a bad design? It seems to me that an entity, like any object in object oriented design, should "know" how to persist itself.
From a patterns perspective you are trying to introduce the ActiveRecord pattern, which some people love, some people hate. So asking if this is bad design might turn religious very quickly :)
Having said that it is a common pattern, unfortunately it is not natively supported by the EF.
There are a number of problems with your code:
1) ContactInstance can't be treated as a Contact, which is what you appear to be trying to do, in EF, if you have a derived type in the CLR (i.e. ContactInstance) it must correspond to a derived type in the Entity Model too. (i.e. an Entity type called ContactInstance) which I suspect you don't have. I'm guess you have this just to add the Persist method. Another way to do that is in a partial class (EF works fine with partial classes:
public partial class Contact
{
public void Persist(...){}
}
2) Next your code has some issues with Entities potentially being attached to multiple ObjectContexts, for example if you write this code:
Contact c = new Contact();
c.Firstname = ...;
c.Surname = ...;
c.Persist();
c.Surname = ...;
c.Persist();
It will fail - in the second call to Persist() - because an Entity can only be attached to one Context at a time:
The first Persist(). adds the entity to one context.
And the second Persist() will attempt to add the same entity to another context. Exception time!.
The workaround for this is to have an Ambient context somehow, using something like ThreadBound statics or something, but then you have to deal with all sorts of tricky issues.
Anyway the moral of the story is that what you are trying is possible using EF, but it isn't easy, you have to really think through things like ObjectContext lifetime, issues like attach / detach etc.
Hope this helps
Alex James
Former EF team member

Categories

Resources