Techniques used with Entity Framework navigation properties - entity-framework

Starting to explore EF4.3.
Using navigation properties makes things very easy, although I have a concern in one area, where I'd appreciate some advice on how other people deal with this scenario.
Take the scenario - Store.Programme.ProgrammeAccountNumber when lazy loading nested properties.
Store is the entity I'm querying.
Programme is an entity, and also a navigation property of Store, and ProgrammeAccountNumber is a property of Programme.
To get the original entity, I write something like this:
public static IQueryable<Store> FindActive()
{
var r = new ReadRepo<Store>(Local.Items.Uow.Context);
return r.Find(s => s.StoreStatusId == (int)StoreStatus.Active);
}
But lets suppose that Programme has it's own status fields:
var store = StoreBL.FindActive()
.Where(s => s.Programme != null && s.Programme.ProgramStatusId = (int)ProgrammeStatus);
It's not easy to remember all the conditions for each entity each time the query extends beyond the original entity.
Imagine a chain of properties where I have a product, that has a start/end dates and a status, that belongs to a store, that has a programme with a status and is valid if the category it operates is live.
I got to thinking there must be a technique for dealing with this effectively, or is it a case of using Lazy Loading sparingly?
Any advice appreciated.

Related

Get entity facets and other metadata on runtime

I have .NET 4.0 WinForms Application, and I use Entity Framework 5 with Model First Approach. In VS EF Designer, I have created a dozen or so entities with a lot of scalar properties of String type, then in Properties Toolbar I have configured parameters (i.e. General parameters, Facets Parameters) for them, to fit DB requirements.
In BL layer I am able to validate entity object in purpose to check whether it contains correct values, for example by using DbContext.Entry(Of T)(entity).GetValidationResult() method. But I need to develop also GUI layer input fields validation for WinForms. I would like to implement dynamic GUI validation, based on metadata values of entity set properties, to have BL validation synchronized with GUI validation, and to avoid redundancy of source code written.
My question is: How can I get metadata values, particularly facets metadata values (i.e. Fixed Length, Max Length, Nullable) of auto-generated entities on runtime?
As I know, there is a possibility to take advantage of data annotations based on properties attributes in manually created partial class. However, in Model First approach, this solution may also involve redundancy issues and synchronization problems with metadata from VS EF Designer Properties Toolbar and Database.
This should help you get started, but you'd need to get to debugger and test specifically to get what you need...
A sample code...
using (var db = new MyContext())
{
var objectContext = ((IObjectContextAdapter)db).ObjectContext;
var baseset = objectContext
.MetadataWorkspace
.GetEntityContainer(objectContext.DefaultContainerName, DataSpace.CSpace)
.BaseEntitySets
.First(meta => meta.ElementType.Name == "YourEntityClassName");
var elementType = objectContext
.MetadataWorkspace
.GetEntityContainer(objectContext.DefaultContainerName, DataSpace.CSpace)
.BaseEntitySets
.First(meta => meta.ElementType.Name == "YourEntityClassName")
.ElementType;
EdmMember member = elementType.Members[2];
Facet item;
// if (member.TypeUsage.Facets.TryGetValue(EdmProviderManifest.StoreGeneratedPatternFacetName, false, out item))
if (member.TypeUsage.Facets.TryGetValue("StoreGeneratedPattern", false, out item))
{
var value = ((StoreGeneratedPattern)item.Value) == StoreGeneratedPattern.Computed;
}
But that's just part of the story.
What I realized is that's working in some cases (thus you need to experiment a bit) depending on what you need. But you also have other spaces in there - e.g. the SSpace. So e.g. for table names this works better...
var ssSpaceSet = objectContext.MetadataWorkspace.GetItems<EntityContainer>(DataSpace.SSpace).First()
.BaseEntitySets
.First(meta => meta.ElementType.Name == "YourTableName");
...and then private Table property.
In your case you should most info in there - but e.g. the above store generated is not populated there - but in some other 'space' I guess (more in one of the links on that).
And take a look at the following links:
Get Model schema to programmatically create database using a provider that doesn't support CreateDatabase
How I can read EF DbContext metadata programmatically?
How check by unit test that properties mark as computed in ORM model?

Entity Framework Code First 4.3 / LINQKit predicate for related table

I am using Entity Framework 4.3.1 with a Code First approach. Also, I am using LinqKit so as to use the PredicateBuilder.
If I have tables like so:
Location, TimeZone (Many:1)
..and I wish to have something like so:
Expression<Func<TimeZone, bool>> pred = PredicateBuilder.True<TimeZone>();
pred = pred.And(tz => tz.TimeZoneCode == "EST");
List<Location> locations = context.Locations
.AsExpandable().Where(pred)
.Select(loc => loc).ToList();
This does not work, because the predicate is built to accept a TimeZone, but the Where() method receives a Location.
I can rewrite the predicate like so, but I do not want to, because I want to have a predicate factory that creates predicates for specific types (I do not want to use the Navigator properties in this manner):
Expression<Func<Location, bool>> pred = PredicateBuilder.True<Location>();
pred = pred.And(loc => loc.TimeZone.TimeZoneCode == "EST");
What syntax could I use (if any) to use the predicate as constructed in the first example, where it takes a TimeZone, rather than have it take a Location and walk the tree via the navigation properties (as this is less reusable). It would be nice if there was a way to leverage the knowledge that EF has about the navigation properties in the first place, and be able to use a predicate scoped to the type of the navigation property.
After about a week's worth of struggling, I found out that you can in fact do this. The steps are:
Define a Predicate that is the query for your inner property (subPredicate)
Invoke that subPredicate from within another Predicate (predicate), against the property of the parent object.
Expand your predicate when using it in your Where clause.
Here's the revised code for your example:
var subPredicate = PredicateBuilder.True<TimeZone>();
subPredicate = subPredicate.And(tz => tz.TimeZoneCode == "EST");
var predicate = PredicateBuilder.True<Location>();
predicate = predicate.And(l => subPredicate.Invoke(l.TimeZone));
List<Location> locations = context.Locations
.AsExpandable().Where(pred.Expand())
.Select(loc => loc).ToList();
Just to update this: it turns out that the intent of these kinds of predicates is to filter the primary entity. The mental concept is: decide which entities you would like to return, and return them. EF is apparently not designed for this kind of deep predicate application on child entities.
One person (I don't remember where) made a great point: If the children were pre-loaded, you would not expect a partially-loaded collection. Thus, it would not make sense to have an Invoice entity, for example, but only half of the Invoice Lines.
What I wanted to achieve was more along the lines of EXISTS() or IN(), where you could say "Give me all Invoices where there are Invoice Lines for Product Types 'Nuts' and 'Bolts'". This is feasible, but you may have to apply LINQ or compose your own object. The intent of EF out of the box is to hand you the Invoice, and then you may lazily or eagerly load the Invoice Lines, but not using them as a filter straight from the database.
There are some constructs that I saw to accomplish something close, but the syntax gets very unmanageable very quickly.
Don't fight city hall.

EF 4.0 IsAttachedTo extension method and error An object with the same key already exists

I was getting an error
An object with the same key already exists in the ObjectStateManager.
The ObjectStateManager cannot track multiple objects with the same
key.
After i googled it i found IsAttachedTo extension method there:
Is is possible to check if an object is already attached to a data context in Entity Framework?
here is my code:
foreach (string s in types)
{
Subscription subscription = new Subscription { Id = Int32.Parse(s) };
if (service.repository._context.IsAttachedTo(subscription))
service.repository._context.Detach(subscription);
service.repository._context.AttachTo("Subscriptions", subscription); //error here
horse.Subscriptions.Add(subscription);
}
But when the subscription with the same key appeared in the foreach loop the extension method IsAttachedTo returning false every time, it is does not detect that there is already such entity attached. And in result i am getting the same error:
An object with the same key already exists in the ObjectStateManager.
The ObjectStateManager cannot track multiple objects with the same
key.
Why it is could be?
What can i do to fix that?
I have little code review for you because your sample code scares me.
You probably read a lot about fancy design patterns and layered architectures and you started to use them yourselves. Unfortunately you missed the main point. What the hell is this?
service.repository._context.XXX
Why do you bother with any service layer or repository layer if they don't encapsulate their logic? Why do you expose repository on the service? Nobody should know about service internal implementation? Even worse why do you expose context on the repository? That spoiled the whole point of the repository!
There are a lot of supporting rules for writing high quality object oriented code. One of this rules is called Law of Demeter. You don't have to follow each rule, you also don't have to follow rules all the time but in case of layered architecture this law is a must.
If you have three layers A -> B -> C the layer A can call methods on the layer B but it doesn't know about C and it cannot reach its methods. If it can, it is not a new layer but it is the same layer as B and the layer A doesn't need to call it through B, it can call it directly.
In your example you have just exposed D to A because A is current layer, B is service, C is repository and D is context.
One more points about your code. There are well known naming conventions. These conventions are not about I like this and you like that but about the fact that framework you are using follow these conventions strictly so using another one to mix your naming convention with framework naming convention make your code look messy.
I'm sorry, If this was only some example code to make your code structuring clear. I just needed to describe how wrong this code is.
Now to your real problem. The method you have referenced from the related question will not work in your case. I think it will work only if you load the subscription from the database. The reason is that the referenced method uses EntityKey (either internally or directly) to get the entity from context but your new entity doesn't have the entity key yet. I expect that calling TryGetObjectStateEntry for your entity will always return Detached. Entity key it is created during attaching or you have to build it manually.
If you want some IsAttachedTo method try this:
public bool IsAttachedTo<T>(this ObjectContext context, T entity) where T : IEntity
{
return context.GetObjectStateEntries(~EntityState.Detached)
.Where(e => !e.IsRelationship)
.Select(e => e.Entity)
.OfType<T>()
.Any(e => e.Id == entity.Id);
}
And make sure that your entity implements helper interface
public interface IEntity
{
int Id { get; }
}
But to be able to detach attached entity you will need:
public T GetAttached<T>(this ObjectContext context, T entity) where T : IEntity
{
return context.GetObjectStateEntries(~EntityState.Detached)
.Where(e => !e.IsRelationship)
.Select(e => e.Entity)
.OfType<T>()
.SingleOrDefault(e => e.Id == entity.Id);
}
You will have to detach instance returned from this method.
Anyway I would start to think why do you need that for the first place because it looks like your architecture has another wrong concept. Why don't you use attached entities directly? If you don't use them why do you even keep the context with them?
It's likely that IsAttachedTo does not compare by the key (Id) but by object identity. Because you create a new Subscription for every item in the loop the objects are all different instances.
Since you seem to have objects with same Id in your types collection but in the end only want to add one object per key into the context you can perhaps make your life easier by filtering out the duplicates in the first place:
var distinctTypes = types.Distinct();
foreach (string s in distinctTypes)
{
Subscription subscription = new Subscription { Id = Int32.Parse(s) };
service.repository._context.AttachTo("Subscriptions", subscription);
horse.Subscriptions.Add(subscription);
}
This way there should be only one object per key which gets attached to the context.

Entity Framework in n-layered application - Lazy loading vs. Eager loading patterns

This questions doesn't let me sleep as it's since one year I'm trying to find a solution but... still nothing happened in my mind. Probably you can help me, because I think this is a very common issue.
I've a n-layered application: presentation layer, business logic layer, model layer. Suppose for simplicity that my application contains, in the presentation layer, a form that allows a user to search for a customer. Now the user fills the filters through the UI and clicks a button. Something happens and the request arrives to presentation layer to a method like CustomerSearch(CustomerFilter myFilter). This business logic layer now keeps it simple: creates a query on the model and gets back results.
Now the question: how do you face the problem of loading data? I mean business logic layer doesn't know that that particular method will be invoked just by that form. So I think that it doesn't know if the requesting form needs just the Customer objects back or the Customer objects with the linked Order entities.
I try to explain better:
our form just wants to list Customers searching by surname. It has nothing to do with orders. So the business logic query will be something like:
(from c in ctx.CustomerSet
where c.Name.Contains(strQry) select c).ToList();
now this is working correctly. Two days later your boss asks you to add a form that let you search for customers like the other and you need to show the total count of orders created by each customer. Now I'd like to reuse that query and add the piece of logic that attach (includes) orders and gets back that.
How would you front this request?
Here is the best (I think) idea I had since now. I'd like to hear from you:
my CustomerSearch method in BLL doesn't create the query directly but passes through private extension methods that compose the ObjectQuery like:
private ObjectQuery<Customer> SearchCustomers(this ObjectQuery<Customer> qry, CustomerFilter myFilter)
and
private ObjectQuery<Customer> IncludeOrders(this ObjectQuery<Customer> qry)
but this doesn't convince me as it seems too complex.
Thanks,
Marco
Consider moving to DTO's for the interface between the presentation layer and the business layer, see for example:- http://msdn.microsoft.com/en-us/magazine/ee236638.aspx
Something like Automapper can relieve much of the pain associated with moving to DTOs and the move will make explicit what you can and cannot do with the results of a query, i.e. if it's on the DTO it's loaded, if it's not you need a different DTO.
Your current plan sounds a rather too tightly coupled between presentation layer and data layer.
I would agree with the comment from Hightechrider in reference to using DTOs, however you have a valid question with regard to business entities.
One possible solution (I'm using something along these lines on a project I'm developing) is to use DTOs that are read-only (at least from the presentation layer perspective. Your query/get operations would only return DTOs, this would give you the lazy loading capability.
You could setup your business layer to return an Editable object that wraps the DTO when an object/entity is updated/created. Your editable object could enforce any business rules and then when it was saved/passed to the business layer the DTO it wrapped (with the updated values) could be passed to the data layer.
public class Editable
{
//.......initialize this, other properties/methods....
public bool CanEdit<TRet>(Expression<Func<Dto, TRet>> property)
{
//do something to determine can edit
return true;
}
public bool Update<TRet>(Expression<Func<Dto, TRet>> property, TRet updatedValue)
{
if (CanEdit(property))
{
//set the value on the property of the DTO (somehow)
return true;
}
return false;
}
public Dto ValueOf { get; private set;}
}
This gives you the ability to enforce if the user can get editable objects from the business layer as well as allowing the business object to enforce if the user has permission to edit specific properties of an object. A common problem I run into with the domain I work in is that some users can edit all of the properties and others can not, while anyone can view the values of the properties. Additionally the presentation layer gains the ability to determine what to expose as editable to the user as dictated and enforced by the business layer.
Other thought I had is can't your Business Layer expose IQueryable or take standard expressions as arguments that you pass to your data layer. For example I have a page building query something like this:
public class PageData
{
public int PageNum;
public int TotalNumberPages;
public IEnumerable<Dto> DataSet;
}
public class BL
{
public PageData GetPagedData(int pageNum, int itemsPerPage, Expression<Func<Dto, bool>> whereClause)
{
var dataCt = dataContext.Dtos.Where(whereClause).Count();
var dataSet = dataContext.Dtos.Where(whereClause).Skip(pageNum * itemsPerPage).Take(itemsPerPage);
var ret = new PageData
{
//init this
};
return ret;
}
}

Entity Framework Validation & usage

I'm aware there is an AssociationChanged event, however, this event fires after the association is made. There is no AssociationChanging event. So, if I want to throw an exception for some validation reason, how do I do this and get back to my original value?
Also, I would like to default values for my entity based on information from other entities but do this only when I know the entitiy is instanced for insertion into the database. How do I tell the difference between that and the object getting instanced because it is about to be populated based on existing data? Am I supposed to know? Is that considiered business logic that should be outside of my entity business logic?
If that's the case, then should I be designing controller classes to wrap all these entities? My concern is that if I deliver back an entity, I want the client to get access to the properties, but I want to retain tight control over validations on how they are set, defaulted, etc. Every example I've seen references context, which is outside of my enity partial class validation, right?
BTW, I looked at the EFPocoAdapter and for the life of me cannot determine how to populate lists of from within my POCO class... anyone know how I get to the context from a EFPoco Class?
This is in reply to a comment I left. Hopefully this answers your question, Shimmy. Just comment, and I will shorten it or remove it if it doesn't answer your question.
You will need both INotifyPropertyChanging and INotifyPropertyChanged interfaces to be implemented on your class (unless it is something like an entity framework object, which I believe implements these internally).
And before you set a value to this property, you will need to raise NotifyPropertyChanging.PropertyChanging event, using the name of the property in PropertyChangingEventArgs constructor.
And after you set this value you need to raise NofityPropertyChanged.PropertyChanged event, again using the name of the property this is being raised in PropertyChangedEventArgs constructor.
Then you have to handle the PropertyChanging and PropertyChanged events. In the PropertyChanging event, you need to cache the value. In the PropertyChanged event, you can compare and throw an exception.
To get the property from PropertyChanging/PropertyChanged event args, you need to use relfection.
// PropertyName is the key, and the PropertyValue is the value.
Dictionary <string, object> propertyDict = new Dictionary<object, object>();
// Convert this function prototype to C# from VBNet. I like how Handles is descriptive.
Public Sub PropertyChanging(sender As object, e As PropertyChangingEventArgs) Handles Foo.PropertyChanging
{
if (sender == null || preventRecursion)
{
return;
} // End if
Type senderType = sender.GetType();
PropertyInfo info = senderType.GetProperty(e.PropertyName);
object propertyValue = info.GetValue(sender, null);
// Change this so it checks if e.PropertyName already exists.
propertyDict.Add(e.PropertyName, propertyValue);
} // End PropertyChanging() Event
// Convert this function prototype to C# from VBNet. I like how Handles is descriptive.
Public Sub PropertyChanged(sender As object, e As PropertyChangedEventArgs) Handles Foo.PropertyChanged
{
if (sender == null || preventRecursion)
{
return;
} // End if
Type senderType = sender.GetType();
PropertyInfo info = senderType.GetProperty(e.PropertyName);
object propertyValue = info.GetValue(sender, null);
// Change this so it makes sure e.PropertyName exists.
object oldValue = propertyDict(e.PropertyName);
object newValue = propertyValue;
// No longer needed.
propertyDict.Remove(e.PropertyName);
if (/* some condition */)
{
try {
preventRecursion = true;
info.SetValue(oldValue, null);
Throw New Exception();
} finally {
preventRecursion = false;
} // End try
} // End if
} // End PropertyChanging() Event
Notice how I am using PreventRecursion, which is a boolean I forgot to add above these methods? When you reset the property back to its previous value, these events will be recalled.
tl;dr
Now you could derive a single event which inherits from INotifyPropertyChanged, but uses an argument which holds an Object representing the previous value as well as the Property Name. And that would reduce the number of events being fired down to one, have similar functionality, and have backwards compatibility with INotifyPropertyChanged.
But if you want to handle anything before the property gets set (say the property does an irreversible change or you need to setup other properties before setting that variable, otherwise an exception will be thrown) you won't be able to do that.
Overall, this method is a very old way of doing things. I would take Poker Villian's answer and have invalid data able to be entered. But disallow saving to a database.
Entity Framework has some excellent code towards validation. You add validation to your properties via attributes. And then it takes care of the work of processing those attributes. Then you can make a property called IsValid, which calls Entity Framework specific validation. It also distinguishes both field errors (like typing in the wrong characters or having a string too long), and class errors (like having missing data or conflicting keys).
Then you can bind IsValid to controls validation, and they will display a red bubble while invalid data is entered. Or you could just implement IsValid validation yourself. But If IsValid is false, SaveChanges event would need to cancel saving.
btw. The code provided will not compile and is pseudocode only (mixing vb and c#). But I believe it is much more descriptive than c# alone--showing exactly what is being handled.
Concerning your first question, I would simply implement the changes to the associations as business logic. For example, if you add a Teacher class with multiple Student, do not add students like
aTeacher.Students.Add(new Student)
instead, create a AddStudent method
public Student AddNewStudent(string name, string studentID)
{
Student s = new Student( name, studentID);
s.Teacher = this; // changes the association
return s;
}
That way you have full control on when associations are changed. Of course that what prevents another programmer from adding a student directly? On the Student side, you can set the Teacher setter to private (and change the constructor to accept a teacher or similar). On the teacher side, how to make the Students collection non-insertable? I'm not certain... maybe transforming it in a custom collection that doesn't accept inserts.
Concerning the second part of your question, you could probably use the OnVarNameChanging events. If the EntityState is 'New' then you can apply your logic that fetches the real values.
There is also an event that fires when you save changes (OnSavingChanges?) that you could use to determine which objects are new and set some values.
But maybe the simplest solution is to always set the defaults in the constructor and they will get overwritten if the data is loaded from the DB.
Good luck
Create a factory that produces instances for you depending on your need like:
getStudent(String studentName, long studentId, Teacher teacher) {
return new Student(studentName, studentId);
}
getStudentForDBInseration(String studentName, long studentId, Teacher teacher) {
Student student = getStudent(studentName, studentId);
student = teacher;
//some entity frameworks need the student to be in the teachers student list
//so you might need to add the student to the teachers student list
teacher.addStudent(student);
}
It's a serious lack not having an AssociationChanging (that inherits from CancelEventArgs) event.
It bothers me also very much, therefore I reported this to Microsoft Connect Please vote here!
And BTW, I also think this is also stupid that the PropertyChangingEventArgs doesn't inherit CancelEventArgs, since cancelling with an exception is not always the elegant solution, besides, throwing exceptions cost more performance than calling the OnPropertyChangingEvent then check for the returned e.Cancel, so does it cost less than raising the PropertyChangingEvent, which you anyway call them both.
Also an exception can be thrown at the handler anyway instead of marking e.Cancel as true, for those who insist to go the Exception way. Vote Here.
To maybe answer part of your question or expound on ADB's answer you can user ObjectStateManager.GetObjectStateEntry to find the state of the entities and write your custom default logic.
SaveChanges is the method on the context that you can use, or SavingChanges is the event that occurs before SaveChanges is called.
You can override SaveChanges and only call base.SaveChanges if you don't want to abort the change
There is also a ObjectMaterialized event for the context.
Between the two you can stick all your validation and creation code in one location, which may be appropriate if they are complex and include values of other objects etc..