I stumbled upon unexpected behaviour when using Entity Framework with PostgreSql.
When I query context with navigation property inside where clause, its always null and fails. But If I add there Include method pointing to navigational propery it's working
this will work
context.Garages.Include("PostalCode").Where(f=>f.PostalCode.RegionId == regionId)
this will not (PostalCode is null and fails on NullReference)
context.Garages.Where(f=>f.PostalCode.RegionId == regionId)
I don't think I had to add this to query when using MSSQL. Can anybdoy explain this to me.
If you want that your navigation properties be lazy loaded, then you need to declare them as virtual:
public Garage
{
//...
public virtual PostalCode PostalCode {get;set;}
}
In this link you will find the conditions that must follow your entities if you want to enable lazy loading for your entities and to have the Entity Framework track changes in your classes as the changes occur.
If that navigation property is already virtual, the other option that I think could cause that behavior is if you turn off Lazy Loading on your context:
public class YourContext : DbContext
{
public YourContext()
{
this.Configuration.LazyLoadingEnabled = false;
}
}
If you call the Include method, you are going to load the related entity as part of the query. This load behavior is called Eager Loading. On the other hand, if you use Lazy Loading, the related entity is going to be loaded the first time that is accessed, that is the behavior that you looking for.
Related
On previous efforts with old versions of Entity Framework, I'm used to using Eager Loading - so you get your root entity and then gather related entities as required by the use of "Include".
On my current project we've implemented the latest version of EF on a new database, using database-first. Take this class, for example:
public partial class Zone
{
public Zone()
{
this.OverrideCharges = new HashSet<OverrideCharge>();
}
public System.Guid RowId { get; set; }
public string Name { get; set; }
public virtual ICollection<OverrideCharge> OverrideCharges { get; set; }
}
The OverrideCharges object also has a number of sub-properties underneath it, with related entities under those.
We have two contexts, the actual DB context and a set of DTO contexts. The objects for the latter are mostly copies of the former - the Zone_dto object is pretty much a clone of the original. In both, I have turned off Lazy Loading by using:
public CContext(): base("BreezeMetaData")
{
this.Configuration.LazyLoadingEnabled = false;
}
public UDBEntities()
: base("name=UDBEntities")
{
this.Configuration.LazyLoadingEnabled = false;
}
Now, I query my Zone objects by doing this:
public List<Zone_dto> GetZones()
{
List<Zone> zones = _cilContext.Zones.ToList();
List<Zone_dto> zone_dtos = new List<Zone_dto>();
foreach (Zone zn in zones)
{
zone_dtos.Add(Mapper.Map<Zone, Zone_dto>(zn));
}
return zone_dtos;
}
So - no includes. And Lazy Loading is disabled. I would expect to get back a list of Zone objects and their direct properties, but not any related entities.
But what I get back are the Zone objects, plus all their OverrideCharges, plus all the related entities to those OverrideCharges and so on, all the way down the tree.
These data objects are not huge, and it's not a massive problem. But I'm frustrated that I don't understand why I'm getting back all this data that I haven't asked for. Can someone explain?
What you're describing is exactly what I'd expect - you seem to have Lazy and Eager Loading backwards.
Lazy loading means that the context won't load everything - it's lazy, because it does less work, and loads only what you ask for specifically. .Include() is needed when there is lazy loading, because you're telling it not to be lazy about the thing you're Include()ing.
Eager loading means that the context will load all the things you might need, before you ask for them, by following links from the item you requested and loading whatever they lead to. With lazy loading turned off, it doesn't need to be told to Include() things because it will load everything by default. Use of .Include() is referred to as eager loading because you're telling it to use eager-loading behaviour for that property; with eager loading on everything by default, you don't need .Include().
Set LazyLoadingEnabled = true; and see what happens.
It may be because of the virtual keyword. A virtual ICollection will be lazy-loaded.
See this SO link.
Im writing an web application with MVC using Entity Framework for my backend logic. My problem is that I have an entity that has certain fields that should never be changed on an update. I am not really sure what the best way to solve this problem would be. There is going to be a lot of data processed in my application, so I cant afford to just hack up a solution.
Is it possible to just define the fields as readonly in the POCO entities ? Or should I write and entity framework extension class that validates all updates. Could it be done in the mapping files between EF and the actual database?
I am relatively new with EF, so I hope some of you might be able to give me some pointers!
Thanks!
If you are using .NET 4.5 and EF 5 (i.e. MVC 4), you can simply set IsModified = false on the individual properties in question. This has the benefit of sticking close to the default out-of-the-box MVC conventions.
For example, if you have a CreatedBy field that shouldn't be touched when the record is updated, use the following in your controller:
[HttpPost]
public ActionResult Edit(Response response)
{
if (ModelState.IsValid)
{
db.Entry(response).State = EntityState.Modified;
db.Entry(response).Property(p => p.CreatedBy).IsModified = false;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(response);
}
Note that the IsModified line is the only change from the default controller action.
You MUST put this line AFTER setting .State = EntityState.Modified (which applies to the record as a whole and adds the record into the db context).
The effect is that EF will not include this column in the SQL UPDATE statement.
I am still (very) shocked that there are no [InsertOnly] or [UpdateOnly] attributes similar to [ReadOnly]. This seems like a major oversight by the MVC team. Am I missing something?
I'm not fully satisfied with this solution because it's a hack: You're telling EF that no change was made when what you really mean to say is "HANDS OFF". It also means that you have to use this code anyplace where the field could be updated. It would be better to have an attribute on the class property.
(Apologies for posting to an older thread, but I've not see this solution anywhere else. ViewModels are robust but a lot of work, and EF was supposed to make things easier, not harder...)
Well I would advice against ever using the EF classes in the View. You're best bet is to construct ViewModel classes and use Automapper to map them from the EF classes.
When you are updating records in the database though, you can control which fields in the ViewModel are used to update the existing fields in the EF class.
The normal process would be:
Use the Id to get the latest version of the existing object out of the database.
If you are using optimistic concurrency control then check that the object has not been updated since the ViewModel was created (so check timestamp for example).
Update this object with the required fields from your ViewModel object.
Persist the updated object back to the database.
Update to include Automapper examples:
Let's say your POCO is
public class MyObject
{
public int Id {get;set;}
public string Field1 {get;set;}
public string Field2 {get;set;}
}
and Field1 is the field you don't want updating.
You should declare a view model with the same properties:
public class MyObjectModel
{
public int Id {get;set;}
public string Field1 {get;set;}
public string Field2 {get;set;}
}
and Automap between them in the constructor of your Controller.
Mapper.CreateMap<MyObject, MyObjectModel>();
you can if you wish (although I prefer to do this manually, automap the other way too:
Mapper.CreateMap<MyObjectModel, MyObject>().ForMember(dest=>dest.Field1, opt=>opt.Ignore());
When you are sending date to your website you would use:
var myObjectModelInstance = Mapper.Map<MyObject, MyObjectModel>(myObjectInstance);
to create the viewModel.
When saving the data, you'd probably want something like:
public JsonResult SaveMyObject(MyObjectModel myModel)
{
var poco = Mapper.Map<MyObjectModel, MyObject>(myModel);
if(myModel.Id == 0 )
{
//New object
poco.Field1 = myModel.Field1 //set Field1 for new creates only
}
}
although I'd probably remove the exclusion of Field1 above and do something like:
public JsonResult SaveMyObject(MyObjectModel myModel)
{
var poco;
if(myModel.Id == 0)
{
poco = Mapper.Map<MyObjectModel, MyObject>(myModel);
}
else
{
poco = myDataLayer.GetMyObjectById(myModel.Id);
poco.Field2 = myModel.Field2;
}
myDataLayer.SaveMyObject(poco);
}
note I believe that best-practise would have you never Automap FROM the ViewModel, but to always do this manually, including for new items.
I just asked a very similar question, and I believe the answer to that one may help out a lot of folks who stumble across this one as well. The OP mentions that these are fields that should never change, and using PropertySaveBehavior.Ignore ensures this. With the existing answers to this question, you need to make custom save methods or introduce mapping where it might not make sense. By setting the AfterSave property behavior instead, you can prevent this from being possible in EF altogether.
In my project, I am generically accessing a property that is on an abstract class so I have to set it like this:
MyProperty.SetAfterSaveBehavior(PropertySaveBehavior.Ignore);
If you're accessing it directly on a known class, you'd use this:
...
.Property(e => e.YourProperty)
.Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Ignore);
Using EF with Winforms in C#. I’d like to add full custom properties to our entities, using partial classes. All entities already have partial classes with validation stuff and some more so I’d just add the properties that I need. By full property I mean property with getter and setter so not just a computed/readonly property. I want to this mostly to get around working directly with some DB mapped properties which are badly designed or have other problems.
For example, one case would be like this:
// entity class, generated
public partial class Customer
{
public string Spot {get;set}
}
// partial class, manually changed
public partial class Customer
{
public int? xxxSpot
{ get { return Int32.Parse(Spot.Trim()); } // some code omitted
{ set { Spot = value.ToString().PadLeft(5); }
}
So my custom properties will be built around existing, DB mapped properties of the entity. I’d like to use these custom properties like normal ones, ie to bind them to UI controls and so on. I’ve tried one and so far it works great.
Is this a good idea? If not, why ? And what else should I consider when doing this?
You have answered your own question - it works and there is no reason why to not do that. If you want to improve design of your entities you can even try to change visibility of your mapped properties to ensure that other classes must use only your custom properties with additional logic.
I am currently developping an application which object model and persistence layer is built using the Entity Framework model designer.
One of the requirements I have is to provide a status to my entities that could let me know whenever they are in a "dirty" state (modified), when the status change occurs and, most important, working in a disconnected mode. So I started modifying the T4 template to add a IsDirty boolean property upon generation of those entities, added an event that is fired whenever IsDirty changes and added this.IsDirty = true in the xxxChanged methods of all scalar properties.
Everything works great when the entity is not attached to its context but when attached, whenever a property is changed, thus changing the IsDirty value to false, I receive this exception:
The property 'IsDirty' does not have a valid entity mapping on the
entity object. For more information, see the Entity Framework
documentation.
So what am I doing wrong here? I don't want this property to be mapped in my database as it is just an object status that only matters when the object is "alive". Is there an attribute I should use to decorate the IsDirty property? Or should I derive EntityObject and implement the status mechanism? Or maybe you have any better advice on how to implement this?
Thanks.
Edit: I am using Entity Framework 4.0 with EDM designer.
Here is the piece of code generated into every base entity:
private bool isDirty;
public event EventHandler DirtyStatusChanged;
public bool IsDirty
{
get
{
return this.isDirty;
}
internal set
{
if (this.isDirty != value)
{
ReportPropertyChanging("IsDirty");
this.isDirty = value;
ReportPropertyChanged("IsDirty");
ReportDirtyStatusChanged();
}
}
}
protected void ReportDirtyStatusChanged()
{
var handler = this.DirtyStatusChanged;
if(handler != null)
{
handler(this, EventArgs.Empty);
}
}
I finally found the error myself. The problem lied inside my property setter. Instead of calling ReportPropertyChanged/ing I should have called OnPropertyChanged/ing.
ReportPropertyChanged/ing implies for the context to search for changes between the original and the current entity value but as this property is just a status object that has no mapping to a store, the concept of original value makes no sense, thus making the context failing to find a correct mapping for this property.
Using OnPropertyChanged/ing just fixed it.
I'm using Entity Framework 4.1 code first approach.
I want to make eager loading as my the dafault configuration, and by that avoid using the Include extension method in each fetching query.
I did as recomended in MSDN, changing the simple lazy property at the DbContext constructor:
public class EMarketContext : DbContext
{
public EMarketContext()
{
// Change the default lazy loading to eager loading
this.Configuration.LazyLoadingEnabled = false;
}
}
unfortunately, this approach is not working. I have to use the Include method to perform eager loading in each query. Any ideas why?
Thanks in advance.
There is no default configuration for eager loading. You must always define Include or create some reusable method which will wrap adding include. For example you can place similar method to your context:
public IQueryable<MyEntity> GetMyEntities()
{
return this.MyEntities.Include(e => e.SomeOtherEntities);
}