I am not interested in disabling lazy loading for the entire context. I want only to selectively disable lazy loading for a few key navigational properties.
With the Code First method, I understand how to selectively disable lazy loading:
public virtual Person Requestor { get; set; } //lazy loading enabled
...
public Person Requestor { get; set; } //lazy loading disabled
However with the Database First method, this is code generated from a template so this modification is going to be lost on the next regeneration.
Is there a way to modify the model or template generator for such selective disabling of lazy loading?
I don't know of a way. But if you are going to use the Entity code generator you could build in a warning system so that when the code is re-generated you get notified immediately (depending on your build strategy).
So what I would do is for the selected entites, say the entity is Request and the property in question is Requestor then write a test to assert that the property is NOT virtual
[TestMethod()]
public void RequestPropertyRequestor_MustNotBeVirtual() {
PropertyInfo[] properties = typeof(Request).GetProperties()
.Where(p => p.GetGetMethod().IsVirtual).ToArray();
Assert.AreEqual(0, properties.Count(p => p.Name == "Requestor"), "Model Code Regenerated - change the Request Entity");
}
Not sure of the accuracy of the reflection code but you get what i mean. This way when the entities are regenerated and you have amended the code, the test fails. early warning system
OR
you could turn off code generation and use POCO's.
Recommended Change
If you don't wanna turn off code gen then modifying the T4 template is the way to go. Just
set the "Code Generation Stategy" to None in the properties of the EDMX designer so that the default generation doesn't occur. This results in no derived DbContext or entity classes
in the EDMX designer, right click on the drawing surface and select "Add Code Generation Item". There should be generators listed there, if not just install one through NuGet. Select the EF5 DbContext one.
Find the T4 template for the entity generation and modify.
You can modify the Entities.tt file. More specifically modify the "AccessibilityAndVirtual" method to handle your specific situation. As this template is specific to your current project you do not have to worry about reuse in other projects. You should be able to selectively define which property names you want to exclude from lazy loading. Happy coding.
if I understand you correctly what you want is .Include("Requestor")
Person person =
context.Persons.Include("Requestor").FirstOrDefault();
this would get a Person and the Requestor in one trip to the db for that query.
Edit:
Looking a bit more, this was assuming you had the Property of Requestor on the Person entity, you can however just change this to the appropriate entity and property.
Related
I am trying to generate a method for each of my Foreign Keys in my Entities to return a list of records based on that foreign key. I know of a way of determining the Primary Key:
foreach (var edmProperty in simpleProperties)
{
bool isPrimaryKey = ef.IsKey(edmProperty);
if(isPrimaryKey)
{
//do stuff
}
}
Is there a way of finding the Foreign Keys?
I am using EF 6 with Visual Studio 2013.
Thanks
Don't do this. For many reasons:
It breaks persistence ignorance. POCO's are not supposed to know anything about the data layer. You may even have POCOs defined in a separate assembly that has no reference to EF.
Methods like GetByCountryID are typically repository methods, they don't belong to an entity class.
Static methods shouldn't be scattered over a class model. They're typical for utility classes or factories (it could make sense to have a method like City.New()).
How would you know that City has a GetByCountryID method? There may even be more classes having the same method.
The object(s) obtained by the method are in no way related to a City instance, but its location seems to intend such an association.
If you remove the property Country from the EDMX (e.g. because it's never used), the method also disappears.
The main reason: there is no substitute for navigation properties. If you want to get Categories and their Products you have to load them in a way that EF knows how to associate them. You either do this by Include, or by including them in a projection, or by lazy loading, or by fetching the Products later, but all in the same context. Your proposed methods can only produce dissociated entities, and disconnected too (i.e. not attached to a context).
There are other patterns to hide data layer details from other application layers, for instance repositories with dependency injection.
Here's how I get the Foreign Key Property name.
public IEnumerable<NavigationProperty> GetParentNavigationProperties(EntityType type)
{
return type.NavigationProperties.Where(np => np.DeclaringType == type && np.ToEndMember.RelationshipMultiplicity != RelationshipMultiplicity.Many);
}
I have started working out with Entity Framework (EF) for an MVC n-tier application. It would seem that very obvious that this being a web application (which is stateless), I would have to use detached object models. There is no ambiguity with doing an Add operation. However when doing an edit there are here are two ways
Fetch the original object in context, attach the updated object and
then save to database. Something like mentioned in answer to this
question
EF4 Context.ApplyCurrentValues does not update current values
Set individual modified properties explicitly using the IsModified property of individual fields of the object like
mentioned in this article
http://msdn.microsoft.com/en-us/data/jj592677.aspx
Method 1 has disadvantage of having to load object into memory from database each time an update needs to be performed.
Method 2 would require having to manually pass which fields to be set as IsModified to true from wherever the object an be updated. So for e.g. for each object, I may need to create a boolean collection object for each field of the object.
e.g.
SaveEntity(EntityClass e, EntityStateClass ec)
{
context.Entry(e).Property("Name").IsModified = ec.NameState;
context.SaveChanges();
}
class EntityStateClass{ public bool NameState;}
I would prefer method 2 simply for the sake of performance but I am hindered by the n-tier architecture and repository pattern I am using. My Repository interface restricts save method for any object to be
SaveEntity(EntityClass e);
So I cannot pass the "state" object. Context class is not available and should not be available outside DAL. So I cannot set property outside. Is there any "proper" way to achieve this ?
Note: Self-Tracking Entity is also out of question since I cannot send entities with state to client (the browser) since I am intent on keeping the html lightweight.
EDIT: After a lot of thinking, I am trying to use following mechanism to keep track of modified state for each field in my domain class
Declare a partial class for entity class.
For each field that is updateable, declare a boolean property like "IsModified_FieldName"
Set the "IsModified_FieldName" property when the field is set.
However for this I need Entity Framework to generate explicit properties for me instead of implicit properties that it auto-generates. Does EF provide an handle to do this ?
Here is sample code of what I am trying to achieve
//Save Method for class EntityClass.
SaveEntity(EntityClass e)
{
context.Entry(e).Property("Name").IsModified = e.IsModified_Name;
context.SaveChanges();
}
//EntityClass is class autogenerated by EF
public partial class EntityClass
{
//This is auto-generated property by EF
public string Name {get; set;}
/* This is what I would like EF to do
private string name;
public string Name
{
get {return Name;}
set {
name = value;
//this is what I would like to do
this.IsModified_Name = true;
};
}
*/
}
//This is another partial definition for EntityClass that I will provide
public partial class EntityClass
{
//This property will be set to true if "Name" is set
public bool IsModified_Name {get; set;}
}
PS: It seems the information I have provided is not sufficient and therefore there are no responses.
I am using DbContext (Database first model)
EF auto-generates the class files for me. So each time I update my database, the class files are regenerated.
To your concrete question: The entities are generated by a T4 template and it should be possible to modify this template (which is in text format) to generate the entities in a way you want to shape them.
But I have a few remarks about your concept:
In a web application data are usually changed by a user in a browser. To have a definite knowledge what really has been changed you need to track the changes in the browser (probably by some Javascript that sets flags in the data (a ViewModel for example) when a user edits a text box for instance).
If you don't track the changes in the browser what happens? The data get posted back to the server and you don't know at the server side (with MVC in a controller) which property has been changed. So, your only chance is to map all properties that has been posted back to your EntityClass and every property will be marked as Modified, no matter if the user really did a change or not. When you later call SaveChanges EF will write an UPDATE statement that involves all those properties and you have an unnecessary overhead that you you want to avoid.
So, what did you win by setting individual properties instead of setting the whole entity's state to Modified? In both cases you have marked all properties as Modified. Exceptions are partial changes of an entity, for example: You have a Customer entity that has a Name and City property and a view that only allows to edit the Name but not the City and a corresponding ViewModel that only contains a Name property. In this case your procedure would only mark the Name property of the Customer entity as Modified but not the City. You might save here a little bit because you don't save the City property value to the database. But you still save the Name even if it didn't change.
If you use solution 1 (ApplyCurrentValues) you have to load the entity first from the database, yes, but it would only mark the properties as Modified that really changed compared to their values in the database. If the user didn't change anything no UPDATE would be written at all.
Keep in mind that you are only at the beginning to implement your concept. There are other changes to the data that can happen in the browser than only scalar property changes, namely relationship changes. For example a user changes the relationship from an Order to a Customer or you have a view that has an Order and a collection of OrderItems and the user cannot only edit the Order header but also edit the OrderItems and remove and add new OrderItems. How do you want to recognize when the data come back from the browser to the server which collection item has been added and which has been removed - unless you track all those changes in the browser and send tracking information back to the server in addition to the actual data or unless you reload the Order and OrderItems from the database and merge the changes into the original entities from the database?
Personally I would vote for option 1 for these reasons:
You can use real POCOs that don't carry additional tracking information. (BTW: I have some doubt if you aren't reinventing the wheel by implementing your own tracking that EF change tracking proxies provide out of the box.)
You don't need to track changes in the browser which can become quite complex and will require Javascript in every Edit view to write change flags into hidden form fields or something.
You can use standard features of EF without having to implement your own tracking.
You are required to load entities from the database when you want to update an entity, that's true. But is this the real performance bottleneck in a web application where data have to run through the wire back and forth (and reflection (which isn't really known as to be fast) is involved by the model binder)? I have nothing said if your database is remote from the web server and connected by a 9600 baud modem. But otherwise, your plan is not only premature optimization, it is kind of premature architecture. You are starting to build a potentially complex architecture based on "it could be slow" to solve a performance problem that you actually don't know of whether it really exists.
Using Entity Framework 5, Visual Studio 2010 with the Entity Framework Power Tools (Beta 2) extension.
Here is my database table structure:
I used the Reverse Engineer Code First function of the aforementioned extension, which generated the POCO classes and some 'mapping' files (not sure if that's the formal parlance) and a single DbContext-derived class. Other than the change I describe next, all of these generated classes are as-generated by the power tool.
In the Category.cs file, I added the following code to help flatten the object graph a bit:
private ICollection<Product> m_Products = null;
public ICollection<Product> Products
{
get
{
if (m_Products == null)
{
m_Products = new List<Product>();
foreach (var categoryProduct in CategoryProducts)
{
m_Products.Add(categoryProduct.Product);
}
}
return m_Products;
}
set { m_Products = value; }
}
I get the following exception, which I know must have something to do with the mappings, but I just can't quite figure this out.
Unhandled Exception: System.Data.EntityCommandExecutionException: An error occurred while
executing the command definition. See the inner exception for details.
---> System.Data.SqlClient.SqlException:
Invalid column name 'Category_CategoryId'.
If I need to post more information, such as the specifics of the mappings, just let me know and I'll do it. I wanted to keep this as short as possible, but I realize I've omitted some things that, for those unfamiliar with the code generated by the tool, may leave one wanting for more details.
You've added a navigation property to your model and so EF is trying to map that to your database. "Code First" means your code model defines your database schema.
Try adding the [NotMapped] attribute to your helper properties to tell EF to ignore them.
In case you've created DB scheme automatically and you are not using strategies like (DropDatabaseAlways/DropDatabaseIfModelChanges) - other words: you are really in Reverse Engineering, it seems that you have to manually add column "CategoryId" on "Category" table.
In case, you don't want to work with the property (I mean in DB), you can use Data Annotation [NotMapped] or Fluent API modelBuilder.Entity<Category>().Ignore(x=> x.CategoryId)
Finally it is possible that problem can be in mapping. I don't know whether you are using data annotations or Fluent API but EF may automatically looks for some db column (logical behavior derived from the model) and can not find it. In this case I recommend you make a revision of the mapping.
The OP already solved their problem, but I've had a similar error with a different solution. So here it is in case others need it:
I was missing a navigation property on one side of a 0..1 relationship between entities. Once I added an appropriate navigation property to the entity that was missing it, the problem was solved.
A bit more details: I had two entities with a 0..1 relationship using a FK. Entity A (parent) had a FK to Entity B (child). The child entity B had a navigation property to entity A, but A did not have a navigation property to B. After adding this, the problem was solved.
Scenario:
A huge Patient class/entity with around 100 properties. But in the webpage I only need to display the contact information (only around 10 properties) to update. Do/Can I create a ViewModel to do that?
I have only used ViewModel to read data before. Can it be used to update data?
EDIT:
Okay, to summarize what I have found so far.
Use AutoMapper to map the ViewModel (only contains the properties to be updated) back to the original big EntityClass.
An example is:
[HttpPost]
public virtual ActionResult Edit(EditUser user)
{
var domain = uow.Users.Create();
domain.Id = user.Id;
uow.Users.Update(domain);
AutoMapper.Mapper.Map<EditUser, Example.Core.Data.User>(user, domain);
uow.Save();
return View();
}
Create another entity called PatientSummary in the EDMX model, which only contain the necessary properties. Manually do the mapping in the EDMX designer. Then use this reduced entity for the Patient contact update web page.
Personally, I feel there must be a better way to do that. Any comment?
Yes upon save simply load your object and then use automapper to copy the properties back to your object or manually set them on your EF class.
EF will know which props changed and only send updatea for those changed properties.
I actually posted a couple of questions a little while back on a related topic - question 1 and more specific question 2.
I wasn't a hundred percent happy with the one answer that I got so far on question 2 but the experts seemed to agree that it is a good idea to use view models. For one it saves you from manually making sure that the "other" 90 properties don't get overwritten in the database by the generated UPDATE statement.
I have 3 tables in my database - Conference, ActivityTypes and a joining table ConferenceActivities. Each conference may have a zero or many standard activities and each activity may occur in zero or more conferences.
Conference (ConferenceID, ConferenceName)
ConferenceActivities (ConferenceID,ActivityTypeID)
ActivityTypes (ActivityTypeID, ActivityTypeDesc)
I used Entity framework over my existing database, with the .tt templates in a MVC3 app I generated a DbContext and the POCO objects, noting that it generates just two objects, ActivityType and Conference which is nice it seems to understand the intermediary table.
It also adds a collection of activities to my conference
public virtual ICollection<ActivityType> ActivityTypes { get; set; }
And a collection of Conferences to my Activity.
public virtual ICollection<Conference> Conferences { get; set; }
I would like to return using JSON an object matching a specific conference.. that includes the ActivityTypes. Some might described this object as 'shaped' or 'jagged' because it has a collection within it.
I'm using code like the following although I've tried many different variations incase I had the syntax wrong but I still get a runtime error about recursion.
public JsonResult GetConference(int conferenceId)
{
Conference x = context.Conferences.Include("ActivityTypes").FirstOrDefault<Conference>(i => i.EventID == eventId);
return Json(x, JsonRequestBehavior.AllowGet);
}
It doesn't seem to work 'out of the box' and I see a lot of Stack Overflow questions that seem to relate but despite trying numerous different approaches but all create an error about recursion or parameterless constructors.. I am starting to doubt whether this is even possible.
I have tried attaching [IgnoreDataMemberAttribute] or [ScriptIgnore] to different properties to stop it trying to serialise the recursive relationship (I think the form is irrelevant but when your desperate..) and I still get the same error.
I've tried this sort of approach which generates the parameterless error
var thing = from r in context.Conferences
select new
{
r.ConferenceID,
r.ConferenceName,
ActivityTypes = new List<ActivityType>(
(from c in r.ActivityTypes
select new ActivityType()
{
ActivityTypeDesc = c.ActivityTypeDesc,
ActivityTypeID = c.ActivityTypeID
}).Cast<ActivityType>())
};
return Json(thing, JsonRequestBehavior.AllowGet);
Another suggestion was to set the Lazy Loading Enabled property on the model to false.. which made no difference I still get the recursion error.
I've tried removing the Virtual keyword which I belive turns off the lazy loading.. and trying with .Include(..) but again no joy.
Another suggestion was to change the accessor from public to internal however that made no different to the serialization.
Somebody also suggested removing the collection of Conferences from the ActivityType class, not really what I want to do.. but doing that just produces an error `Schema specified is not valid.' anyway.
I am using I believe the latest version nuget and the associated EF, scaffolding and templates.
Is what I'm trying to achieve something that should work out of the box? If so what setting(s) could I be missing and if not, what is the best practise here - the only way I know I can make this work is to build up the object manually myself.
Suggestions or a link to a complete working demo (I've seen a lot of suggestions and code snippets that just don't seem to work!!) appreciated. I'm certain somebody's done this and got it working surely.
don't pass your model classes around. create a viewmodel with the data you need for the view, or, in your case, the json output. i see where you tried projecting it into an anonymous type, but project it into a concrete viewmodel and it should work perfectly.