So, we are porting an old wpf app into .net core wpf. As part of the effort we are also moving the data layer to EF.net core.
- Since we use Prism MVVM, within the DI service context we keep a live data context which tracks the entities being shown and edited by user through the wpf front end and via service.
- In order to implement "undo" functionality, we track the objects using
entity.HasChangeTrackingStrategy(ChangeTrackingStrategy.ChangingAndChangedNotificationsWithOriginalValues);
On edit, the object gets updated, on Reload() it gets reverted from tracked original values. Object wise, the operations are ok, however, the wpf side of things is not working ok. It seems the ef.net core is a very maladjusted citizen of the wpf application, assuming its the sole beneficiary of INotifyPropertyChanged mechanism. Which is, of course, not true in the slightest for WPF.
- EF.net does not seem to use properties when loading, reloading etc. It works directly on underlying fields. As a consequence, NotifyPropertyChanged never fires so grid never refreshes with new data, on say
dbContext.Entry(c).Reload();. So question #1, is there a way to force ef.net to work with properties and not fields? - The ef.net implementation of
INotifyPropertyChangedseems to be flawed. If you invoke PropoertyChanged event on a property, without actually changing it, it will mark the entity asModified, even though it can easily compare original and current value. This prohibits us from manually raising property changed events to control WPF rendering. Not sure how to solve this, or if its even solvable because it only applies to this tracking strategy. I am open to any suggestion on how I can notify WPF elements without riling up ef.net. - Determining the state of the object is rather convoluted operation involving
dbContext.Entry(entry).Statewhich exists outside of any WPF bindings withinDataContexthierarchy. It makes binding on state virtually impossible (for example to change the background of dirty entries or show Save button, etc). We "solved" it by inheriting all our entity classes fromNotifySetterObjectbase class which handlesINotify*implementation and also keeps[NotMapped] bool IsDirtyflag. Needless to say, I dislike this heavily, keeping two unlinked state flags sounds like an accident waiting to happen. I am wondering if you encountered similar problem and if you devised a better, more sane, solution.
EF.net seems to have undergone a breaking change transformation from framework ef.net in terms of being only well suited for detached context scenarios (like asp.net). Are we wasting our time here trying to fit this shoe on wpf? Should we maybe focus on a different OR engine more suited to live contexts?
Before trying to address your questions, let me point out some things:
You are using EF Core 3.0, which currently is in preview (beta), so many things might not work as expected.
If by
ef.netyou mean EF6, i.e. the old project you are porting was using EF6, it's not strongly necessary to switch to EF Core - EF6 is also getting .Net Core support - a preview version is available here.Now regarding your concrete questions:
EF Core can use properties, field or both. This is configurable via fluent API at context, entity and property level. Just the EF Core 3.0 default has changed - you can see that in Breaking Changes - Backing fields are used by default. The link also shows how the get the desired behavior by using
on model (all entities), entity (all entity properties) or property (specific entity property) builders.
So it is by design, hence there is nothing you can do about it. But solving #1 eliminates the need of manually raising
PropertyChangedevent, and the two-way binding seem to work flawlessly.ChangeTracker-TrackedandStateChanged, which (especially the second) can be used to provide state change notifications. But the actual mechanism for that is left for you. For instance, you can use EF Core 2.1+ entity constructor service injection feature to injectDbContextinto entity, which in turn can subscribe toStateChangedevent and raisePropertyChangedfor its own unmappedStateproperty etc.