why can't we get ObjectContext from an EntityObject - c#

It is well know that if we have an EntityObject that there is no way to find the ObjectContext that it belongs to. That's fair enough I guess, but why is it that we can lazy load objects then? Surely the process of lazy loading has to get access to the ObjectContext in order to load the new objects?

The accepted answer is limited in that it can only work if the entity has at least one relationship.
However, this can also be done via reflection:
public ObjectContext Context(EntityObject entity) {
var relationshipManager = ((IEntityWithRelationships)entity).RelationshipManager;
var wrappedOwnerProperty = relationshipManager.GetType().GetProperty("WrappedOwner",BindingFlags.Instance | BindingFlags.NonPublic);
var wrappedOwner = wrappedOwnerProperty.GetValue(relationshipManager);
var contextProperty = wrappedOwner.GetType().GetProperty("Context");
return (ObjectContext)contextProperty.GetValue(wrappedOwner);
}
In VB.NET:
Function Context(entity As EntityObject) As ObjectContext
Dim relationshipManager = DirectCast(entity, IEntityWithRelationships).RelationshipManager
Dim wrappedOwnerProperty = relationshipManager.GetType.GetProperty("WrappedOwner", BindingFlags.Instance Or BindingFlags.NonPublic)
Return wrappedOwnerProperty.GetValue(relationshipManager).Context
End Function
NB: This was tested under .NET Framework v. 4.5.1. YMMV, as this depends on the internal WrappedOwner property and the Context property on the internal BaseEntityWrapper<TEntity> class. Nevertheless, if earlier/leter versions of .NET have different internal properties/classes it should be simple enough to do something similar.
NB: This could further be improved by making it an extension method on EntityObject, and by taking a generic parameter to return a strongly typed ObjectContext. It could also be simplified by using some sort of method to get property values by name.

You are right, given an object, we don't know what context it belongs to, or what session it is attached to. But Lazy Loading happens like this :
var firstPost = _Context.Posts.First()
var commentList = firstPost.Comments
When you say _Context.Posts.First() then one post is loaded.
Then when you say firstPost.Comments that's when the comments list is loaded.
This is possible because the type of your Comments field in your Post is probably an IList or some such generic interface : this is because EF4 can put a proxy list instead of the actual comment list. The proxy list knows about the _Context - knows about which session or context it is attached to. Hence it is able to load an actual list on demand.

Related

RavenDB Dynamic Collection Access

I have request object for some wacky dynamic grid function my boss wrote. One of the properties in this request object is the name of a entity or the collection name for the document store coming into a web api controller.
IDocumentQuery<T> context = session.Advanced.DocumentQuery<T>();
context = AddSearchToContext(context, _searchRequest.Search, _searchRequest.DataFilters.Any());
context = AddFiltersToContext(context, _searchRequest.DataFilters);
context.Take(1).ToList();
RavenQueryStatistics stats = null;
context.Statistics(out stats);
return stats.TotalResults;
Now I have some code that looks like this for testing purposes and so far so good but my main problem is the Type of T. The Type is required for the raven api to realize what collection is being inspected. My problem is I only have a string of the entity name coming in, not the type, and my only idea so far is writing a huge switch statement filled with the same code over and over again for each type.
Is there a "dynamic" or generic way I can avoid repeating all my code over and over again in a switch statement? Can I use reflection? Any tips would be helpful, thank you.
You can use "object", and force the query anyway using:
IDocumentQuery<object> context = session.Advanced.DocumentQuery<object>("dynamic/" + collectionName);

C# Generic Table from DataContext

I'm attempting to create a generic WPF form or page, that when called, will load in data from a LINQ table. Here is the concept:
I have three tables in a LINQ DataContext that are identical (apart from the data within)
TypeID and Type are the columns
I would like to generically pass that data in those tables into my second form depending on which table the user selects (essentially so they can narrow down the list of objects of said Type.
I've seen some responses, (in particular the accepted answer to this one LINQ query with a generic table) that are very close to what I am looking for, but not quite. One issue I have with the above answer is that T must be a reference type.
I've done more searching and found some more answers like:
someClass<T> : <T> where T
But unfortunately these are further from my own context and I am unable to bridge the two concepts of what is happening. Below I have posted what I hope to do.
someDataContext db = new someDataContext();
private void pageLoader<T>(){
newPage n = new newPage(T) //This is where I was hoping I could pass the table(s) to the constructor.
}
And here is the constructor:
newPage(T){
listBox l = new listBox();
l.datasource = T;
}
Any assistance in any direction would be helpful (besides MSDN, please. I've been there and I'm still lost.)
Let start from the top. LINQ is merely an abbreviation for Language Integrated Query. It is interchangeable with Lambda. Different syntax but both accomplish the same task. Querying a collection or datasource. See http://msdn.microsoft.com/en-ca/library/bb397926.aspx
You are referring to the EntityFramework Code First approach of creating a database. LINQ is merely a way to access and manipulate the information within.
With that out of the way, what you are pointing out is a Generic Method and a Generic Class. T is simply a standard naming convention for a generic type. You could use any representation you like. If you are going to be passing in entities, you might use TEntity for example.
See http://www.dotnetperls.com/generic-method
http://www.dotnetperls.com/generic
When you see someClass where T, this is a constraint for type parameters.
And finally, what you have been waiting for...
https://codereview.stackexchange.com/questions/19037/entity-framework-generic-repository-pattern
The following should put you on the right path.
http://blog.gauffin.org/2013/01/repository-pattern-done-right/ <- This would be more of a better starting tutorial

Getting A field or Entity Generically Based on a String Value

I am trying to write a wrapper function for an application.
This application will continually add entities so it would be better if we could write one generic function rather than have to carve out an exception for each item.
For certain reasons we maintain both a GUID and an int key.
When an int key gets updated, we need to update it both in the parent record the child records but since it is possible that at any given time there could be multiple child records with the same int key, we need to get a list of Guids of what we want to update.
Here is some psuedo code of what I am trying to do.
List<string> depenedents = new List<string>();
depenedents.add(table1);
depenedents.add(table2);
depenedents.add(table3);
for(item in depenedents)
{
context.set<type item>();
entities.getguid();
}
Obviously the issue here is with the for loop.
Is it possible to get a list of entities knowing only the string of the entity type? Luckily all of our entities are wrapped to a base class that has a get guid method, but I need to find a way to actually get the entities.
Any help is greatly appreciated.
Something like:
for(item in depenedents)
{
context.GetMethod("Set")
.MakeGenericType(Type.GetType(item))
.Invoke(context, new object[0]);
entities.GetType.GetMethod("GetGuid").Invoke(entities, new object[0]);
}
...should be with roughly what you need. This will invoke the correct type specialisation of the Set generic instance method. Then it will invoke the instance method called "GetGuid" on the entities object.
Or possibly:
foreach(var entity in entities)
{
entity.GetType.GetMethod("GetGuid").Invoke(entities, new object[0]);
}
You'll maybe want to do something with the values returned, but hopefully this answer will point you in the right direction!
(and clearly you could optimise this code substantially to cache reflected types and methods, or to use compiled expressions rather than Invoke() calls)

Querying RavenDB with a reflected type

I load types dynamically through reflection, instantiate the classes, fill them with data and then save them to RavenDB. They all implement an interface IEntity.
In the RavenDB UI, I can see the classes correctly displayed and the meta data has the correct CLR type.
Now I want to get the data back out, change it and then save it.
What I'd like to do
I have the System.Type that matches the entity in RavenDB's CLR meta data, assuming that's called myType, I would like to do this:
session.Query(myType).ToList(); // session is IDocumentSession
But you can't do that, as RavenDB queries like so:
session.Query<T>();
I don't have the generic type T at compile time, I'm loading that dynamically.
Solution 1 - the Big Document
The first way I tried (for a proof of concept) was to wrap all the entities in a single data object and save that:
public class Data {
List<IEntity> Entities = new List<IEntity>();
}
Assuming the session is opened/closed properly and that I have an id:
var myDataObject = session.Load<Data>(Id);
myDataObject.Entities.First(); // or whatever query
As my types are all dynamic, specified in a dynamically loaded DLL, I need my custom json deserializer to perform the object creation. I specify that in the answer here.
I would rather not do this as loading the entire document in production would not be efficient.
## Possible solution 2 ##
I understand that Lucene can be used to query the type meta data and get the data out as a dynamic type. I can then do a horrible cast and make the changes.
Update after #Tung-Chau
Thank you to Tung, unfortunately neither of the solutions work. Let me explain why:
I am storing the entities with:
session.Store(myDataObject);
In the database, that will produce a document with the name of myDataObject.GetType().Name. If you do:
var myDataObject = session.Load<IEntity>(Id);
Then it won't find the document because it is not saved with the name IEntity, it is saved with the name of the dynamic type.
Now the Lucene solution doesn't work either but for a slightly more complex reason. When Lucene finds the type (which it does), Raven passes it to the custom JsonDeserialiser I mentioned. The custom Json Deserialiser does not have access to the meta data, so it does not know which type to reflect.
Is there a better way to retrieve data when you know the type but not at compile time?
Thank you.
If you have an ID (or IDs):
var myDataObject = session.Load<IEntity>(Id);
//change myDataObject. Use myDataObject.GetType() as you want
//....
session.SaveChange();
For query, LuceneQuery is suitable
var tag = documentStore.Conventions.GetTypeTagName(typeof(YourDataType));
var myDataObjects = session.Advanced
.LuceneQuery<IEntity, RavenDocumentsByEntityName>()
.WhereEquals("Tag", tag)
.AndAlso()
//....

What's the best way to store the minimum differential data of a changed object?

I have an object which contains many properties, of many datatypes which is the settings for a search of a large cache. I would like to pass the values which have been changed on this object from the base settings and only the changes. I would also like to pass this information as a very short string.
So what I need is a technique for doing this in C# .NET 4 (pseudo code follows):
var changes = Diff(changedobject, baseobject);
return changes.ToShortString()
and later on a remote machine which only knows the object
var changedobject = CreateObject(diffstring)
Any ideas would be much appreciated.
Thanks
I do not have a code for you but this should be pretty clear
Create a metadata class which using
reflection, gets the properties of the
object and caches the getter method of
each. Then for each property, it does
the same if it is a complex property,
etc ... so you get an object graph
similar to your class. Then when
passed two objects of the same type,
this recursively loops through the
metadata and calls getter in order to
compare and returns the result. You
can also make it generically typed.
Implementaion would be something like this:
public class Metadata<T>
{
private Dictionary<string, Metadata<T>> _properties = new Dictionary<string, Metadata<T>>();
private MethodInfo _getter;
private void BuildMetadata()
{
Type t = typeof (T);
foreach (PropertyInfo propertyInfo in t.GetProperties())
{
// ....
}
}
}
The CSLA.NET framework uses reflection to walk the properties and fields of a type and write them to a hash table. This hash table is then serialized and stored.
The type is called UndoableBase, in the CSLA.NET project.
I can't remember if it records diffs, but the premise is that you need a copy of the state before (in the CSLA case, this would be the previously serialized item).
Assuming you have a copy of an item (an actual copying, not a reference) as a source of originals, then you can use reflection to check each property and add it to the hash table if it has changed.
Send this hash table over the wire.
An alternative and one that I would look at more, is to prefix your serialized item with bit flags denoting what fields are provided in the forthcoming stream. This will likely be more compact than a hash table of name values. You can include this in your reflection solution by first sorting the fields / properties alphabetically (or by some other means). This won't be version tolerant, however, if you store this serialized data across versions of the type.

Categories

Resources