Entity Framework 4: Access current datacontext in partial entity class - entity-framework

I want to extend an EF entity in a partial class with methods and properties. I've done this quite often.
But now I would need to combine data from this entity with data from other entities. I would therefore need to able to access the entities objectcontext (if attached) to make these queries.
Is there a way to get the entities objectcontext from within it?
Thanx!

There is no build in way to get current ObjectContext from entity. Entities based on EntityObject class and POCO proxies uses ObjecContext internally but they don't expose it.
Adding such depnedency into your entities is considered as bad design so you should perhaps explain what you are trying to do and we can find other (better) solution.

Even though it is not recommended, and I myself don't use it (as Ladislav stated: bad design), I stumbled upon a solution:
http://blogs.msdn.com/b/alexj/archive/2009/06/08/tip-24-how-to-get-the-objectcontext-from-an-entity.aspx
Extension Method:
public static ObjectContext GetContext(
this IEntityWithRelationships entity
)
{
if (entity == null)
throw new ArgumentNullException("entity");
var relationshipManager = entity.RelationshipManager;
var relatedEnd = relationshipManager.GetAllRelatedEnds()
.FirstOrDefault();
if (relatedEnd == null)
throw new Exception("No relationships found");
var query = relatedEnd.CreateSourceQuery() as ObjectQuery;
if (query == null)
throw new Exception("The Entity is Detached");
return query.Context;
}
within the entity
var myContext = this.GetContext() as MyEntities;

Related

How to find all managed attached objects in EntityManager (JPA)

Is there a way to get all objects which are currently attached in the entity manager?
I want to write some monitoring code which will report the number of attached objects and their classes.
Meaning finding all objects which were loaded by previous queries and find operations into the entity manager.
I'm using EclipseLink, so a specific solution is good too.
EclipseLink's JPA interface pretty much wraps its native code such that an EntityManager uses a UnitOfWork session underneath (and the EMF wraps a ServerSession). You need to get at the UnitOfWork if you want to see what entities it is managing.
If using JPA 2.0, you can use the EntityManager unwrap method:
UnitOfWork uow = em.unwrap(UnitOfWork.class);
otherwise, use some casting
UnitOfWork uow = ((EntityManagerImpl)em).getUnitOfWork();
From there, the UnitOfWork has a list of all registered (aka managed) entities. You can use the UOW to directly log what it has using the printRegisteredObjects() method, or obtain it yourself using getCloneMapping().keySet().
You can also see deleted objects by using hasDeletedObjects() and then getDeletedObjects().keySet() if there are any, as and the same for new objects using hasNewObjectsInParentOriginalToClone() and getNewObjectsCloneToOriginal().keySet()
you can use JPA in a lot of ways i am still unaware of, and there is a lot going on under the hood in eclipselink that i still do not fully understand, but it looks like it is possible to see into the persistence context. USE THIS CODE AT YOUR OWN RISK. it is only meant to give you a hint that it is possible to inspect the context. (whether the code is right or wrong i'm posting it because it would have helped me when i was trying to decide whether to use eclipselink. there doesn't seem to be much in the way of documentation about how to do this properly.)
public void saveChanges() {
Date now = new Date();
JpaEntityManager jem = em.unwrap(JpaEntityManager.class);
UnitOfWorkImpl uow = jem.unwrap(UnitOfWorkImpl.class);
// inserts
for (Object entity : uow.getNewObjectsCloneToOriginal().keySet()) {
if (entity instanceof IAuditedEntity) {
IAuditedEntity auditedEntity = (IAuditedEntity) entity;
auditedEntity.setAuditedUserId(this.userId);
auditedEntity.setAuditedAt(now);
auditedEntity.setCreatedAt(now);
}
}
// updates
UnitOfWorkChangeSet uowChangeSet = (UnitOfWorkChangeSet) uow.getUnitOfWorkChangeSet();
if (uowChangeSet != null) {
List<IAuditedEntity> toUpdate = new ArrayList<>();
for(Entry<Object, ObjectChangeSet> entry : uowChangeSet.getCloneToObjectChangeSet().entrySet()) {
if (entry.getValue().hasChanges()) {
if (entry.getKey() instanceof IAuditedEntity) {
toUpdate.add((IAuditedEntity) entry.getKey());
}
}
}
for (IAuditedEntity auditedEntity : toUpdate) {
auditedEntity.setAuditedUserId(this.userId);
auditedEntity.setAuditedAt(now);
}
}
// deletions
Project jpaProject = uow.getProject();
boolean anyAuditedDeletions = false;
for (Object entity : uow.getDeletedObjects().keySet()) {
if (entity instanceof IAuditedEntity) {
anyAuditedDeletions = true;
DeletedEntity deletion = new DeletedEntity();
deletion.setTableName(jpaProject.getClassDescriptor(entity.getClass()).getTableName());
deletion.setEntityId(((IAuditedEntity) entity).getId());
deletion.setAuditedUserId(this.userId);
em.persist(deletion);
}
}
}
You can achieve this by inspecting the entities on MetaModel which can be obtained from any EntityManager.
Example usage:
EntityManager em = // get your EM however...
for(EntityType<?> entityType : em.getMetaModel().getEntities())
{
Class<?> managedClass = entityType.getBindableJavaType();
System.out.println("Managing type: " + managedClass.getCanonicalName());
}
This example will print out all of the class types being managed by the EntityManager. To get all of the actual objects being managed, simply query all objects of that type on the EntityManager.
Update:
As of JPA 2.0 you can cache results that will be managed by javax.persistence.Cache. However, with plain JPA there is no way to actually retrieve the objects stored in the cache, the best you can do is check if a certain object is in the Cache via Cache.contains(Class cls, Object pk):
em.getEntityManagerFactory().getCache().contains(MyData.class, somePK);
However, EclipseLink extends Cache with JpaCache. You can use this to actually get the object from the cache via JpaCache.getObject(Class cls, Object id). This doesn't return a collection or anything, but it's the next best thing.
Unfortunately, if you want to actually access objects in the cache, you will need to manage this yourself.
I dont see such an option in the EntityManager interface. There is only a contains(Object entity) method but you need to pass the conrete objects and they are the checked for existentnce in the PersistenceContext. Also looking at the PersistenceContext interface i dont see such an option.

Eager load all properties with Entity Framework

So LazyLoadingEnabled = false apparently doesn't do what I thought it did. And has next to no documentation.
I design my entity trees very carefully. I think hard about every relationship. When I load up an entity that is an Aggregate Root, I want everything that is navigable to from there to load. That's how the Aggregate root concept works after all, if I want something to be weekly related I'd stick an id on the entity and manage the relationship myself.
Is there a way to do this with Entity Framework?
You can try obtaining all NavigationProperties of the element type (in IQueryable). By accessing to the MetadataWorkspace of ObjectContext you can get those properties of a specific type and Include all easily.
Note that I suppose you're using EF5 or later version, whereas DbContext is used. We access to ObjectContext via the interface IObjectContextAdapter. Here is the code:
public static IQueryable<T> LoadAllRelatedObjects<T>(this IQueryable<T> source, DbContext context) {
//obtain the EntityType corresponding to the ElementType first
//then we can get all NavigationProperties of the ElementType
var items = (ObjectItemCollection) ((IObjectContextAdapter)context).ObjectContext.MetadataWorkspace.GetItemCollection(DataSpace.OSpace);
var entityType = items.OfType<EntityType>().Single(e => items.GetClrType(e) == source.ElementType);
return entityType.NavigationProperties
.Aggregate(source, (c, e) => c.Include(e.Name));
}
Note in new version (since EF5), the namespace of ObjectItemCollection (and other metadata items) is System.Data.Entity.Core.Metadata.Edm, while in the old version (before EF5), it's System.Data.Metadata.Emd.
Usage:
yourModel.YourEntities.LoadAllRelatedObjects(yourModel)
//. more query here ...
;
I don't think there's a way to have all of the navigation properties auto-eager load. How about making an extension method instead?
public static IQueryable<Company> LoadCompany(this IQueryable<Company> query) {
return query.Include(x => x.Divisions)
.Include(x => x.Departments)
.Include(x => x.Employees);
}
Example:
var query = from company in db.Companies.LoadCompany()
where company.Name == "Microsoft"
select company;

Need to remove multiple entity objects when using Entity Framework 4.0

I am new in Entity Framework. I want to remove multiple entities in one database context. If I used DBContext.Remove(Object) then It delete only the one entity from database. Please consider my code:
CCSRequest objCCSRequest = DBContext.CCSRequest.Find(ccsRequestId);
if (objCCSRequest != null)
{
DBContext.CCSRequest.Remove(objCCSRequest);
DBContext.SaveChanges();
}
CCProducts objCCProducts = DBContext.CCProducts.Find(ccsRequestId);
if (objCCProducts != null)
{
DBContext.CCProducts.Remove(objCCProducts);
DBContext.SaveChanges();
}
I want to remove entity in both CCSRequest and CCProducts table.
Thank you in advance.
If you want to have a loop that will remove entities of different types you might use this:
object[] entities = new object[]{
DBContext.CCSRequest.Find(ccsRequestId),
DBContext.CCProducts.Find(ccsRequestId)
};
foreach(object entity in entities)
{
DBContext.Entry(entity).State = EntityState.Deleted;
}
Going by the answer to a similar question, you will need to do this in a loop. Please check the answer to this question:
how to delete multiple rows of data with linq to EF using DbContext

How to Determine a property is ComplexType?

I want to implement an IsComplexType() method, which check if the given property from an entity is a ComplexType.
After reading Entity Framework's source code, i find it has implemented one in the "Helper" class, but the class is "internal", so i can't use it outside Entity Framework project.
I wonder if there's a public API in Entity Framework which enable me to do this. If not, how can i implement it?
Try this :
var dbContext = new DbContext("ConnectionString");
var complexType = dbContext.Entry(TEntity).ComplexProperty("ProperyName");
if (complexType != null)
{
// This is a Complex Type
}
Hope this help.

What is the best way to add attributes to auto-generated entities (using VS2010 and EF4)

ASP.NET MVC2 has strong support for using attributes on entities (validation, and extending Html helper class and more).
If I generated my Model from the Database using VS2010 EF4 Entity Data Model (edmx and it's cs class), And I want to add attributes
on some of the entities. what would be the best practice ? how should I cope with updating the model (adding more fields / tables to the database and merging them into the edmx) - will it keep my attributes or generate a new cs file erasing everything ?
(Manual changes to this file may cause
unexpected behavior in your
application.)
(Manual changes to this
file will be overwritten if the code
is regenerated.)
Generally you'd create what is called partial classes to extend your auto-generated objects.
Adding Attributes to Generated Classes
With the "buddy class" concept, linked above, and data annotations I use this extention method. I forget where I got it, so kudos to the original author.
We use it like
List<ValidationResult> errorList = new List<ValidationResult>();
bool bValid = client.IsValid<Client, ClientMetadata>(ref errorList, false);
public static bool IsValid<T, U>(this T obj, ref List<ValidationResult> errors, bool validateAllProperties = true) where T : IValidatableObject
{
//If metadata class type has been passed in that's different from the class to be validated, register the association
if (typeof(T) != typeof(U))
{
TypeDescriptor.AddProviderTransparent(new AssociatedMetadataTypeTypeDescriptionProvider(typeof(T), typeof(U)), typeof(T));
}
var validationContext = new ValidationContext(obj, null, null);
var validationResults = new List<ValidationResult>();
Validator.TryValidateObject(obj, validationContext, validationResults, validateAllProperties);
errors = validationResults;
if (validationResults.Count > 0)
return false;
else
return true;
}
We use partial classes, but if you need them persisted and handled by EF, the "Update Model from Database" option is your best friend.