How to Soft Delete with Entity Data Model - wpf

I have a WPF Application with Entity Data Model.
I would like to set IsDeleted flag to true when entity is deleted instead of deleting from database.
I read many thread here and alot of threads are suggesting to use Modification Function Mapping with the use of conditional mapping.
I used conditional mapping for filtering IsDeleted = true rows and works great.
However, While I'd like to use Modification Function Mapping for just Delete Function, the program give me error, trying to find Function for Insert and Update as well on SaveChanges() method.
I only specified for Delete Function. Is there a way to use only Delete Modification Function and not all Insert, Update, Delete?
If not, is there any other ways that can achieve this? P.S. I read about using Instead Of Delete trigger. However, I would like to avoid it, if possible, since we are developing the program for a mobile application and triggers might slow down the application.
Thank you in advance!

We implemented a soft/logical delete in our Entity Framework 4.1 solution.
I partially described it in this answer:
Partial Answer
First, we added an IsDeleted column to all the tables in the DB that require a soft, or logical delete. In the template, I added inheritance to the IEnforceLogicalDelete interface
public interface IEnforceLogicalDelete
{
global::System.Boolean IsDeleted{ get; set; }
}
In the template where the entities are being defined we added this line:
if(entity.Properties.Where(p => p.DeclaringType == entity && (p.Name == "IsDeleted")).ToList().Count == 1){#>, IEnforceLogicalDelete<#}
This adds the interface after the entity inherits from EntityObject.
Once this is set up, it is time to either create your own save method on the Context, which is what we did, or in the Context.OnSavingChanges event.
As I said above we created our own method (SaveChangesWithHistory) where we also logged all changes (inserts, updates, and deletes) into a history table.
To do the logical delete you need to capture all of the state entries that have an EntityState of Deleted, change their state to Modified, and set your flag. Implementing from the interface makes it easy to do a full delete on any entity that needs it.
foreach (ObjectStateEntry entry in this.ObjectStateManager.GetObjectStateEntries(EntityState.Modified | EntityState.Deleted | EntityState.Added))
{
if (entry.State == EntityState.Deleted)
{
if (entry.Entity is IEnforceLogicalDelete)
{
IEnforceLogicalDelete delete = entry.Entity as IEnforceLogicalDelete;
entry.ChangeState(EntityState.Modified);
entry.ApplyOriginalValues(delete);
delete.IsDeleted = true;
}
}
}

Related

CakePHP 3 Entity Confusion

Here is the issue I am facing all the time since I started to learn CakePHP 3
What is this concept of entity a real world example would help alot.
public function add()
{
// why do we have to create new entity / what is the role of entity here.
$comment = $this->Comments->newEntity();
if ($this->request->is('post','put')) {
// why do we have to use this line after posting / what is the role of this line.
$comment = $this->Comments->patchEntity($comment,$this->request->data);
if ($this->Comments->save($comment)) {
$this->Flash->success('comment submitted successfully.');
} else {
$this->Flash->error('Sorry, comment could not be updated.');
}
}
return $this->redirect($this->referer());
}
Let me open the book for you:
While Table Objects represent and provide access to a collection of
objects, entities represent individual rows or domain objects in your
application. Entities contain persistent properties and methods to
manipulate and access the data they contain.
-
why do we have to create new entity / what is the role of entity here.
Almost everything, if not all, in Cake3 works with entities, what an entity is is explained above. You need to create a new entity so that the FormHelper can work with it, AFAIR it can still work with an array if configured to do so as well but the entity should be used.
The reason entities exist is to abstract the data. Some people think entities are the representation of a DB row - that's wrong. As the book says, they can be a row but don't have to represent a row because the 3.0 ORM can work with other resources as well. In theory you can have a CSV data source that returns an entity per line.
I suggest you to read the entity code in the CakePHP core to get a deeper understanding of what else entities provide, just saying they're "just" a set of properties is to short thought.
why do we have to use this line after posting / what is the role of this line.
The post data is merged into the previously created entity, that's it. Use the API if you have basic questions like that. See the API entry for patchEntity().
In simple word, Entity is a set of one record of table and their relational table, on that you can perform operation without touch of database and encapsulate property of entity (fields of table) as you want.
Advantages of Entity.
Modifying result sets outside of the database (for formatting or otherwise)
Needing to represent both the table and row in the same class.
Data validation was a fucking nightmare.
Inconsistent API in terms of both how we handled things internally as well as what (and how) we returned stuff.
Other random stuff as you want.
You can do run-time modification of result sets. Just add a method to your entity to return results in the way you want. This also means you can use composition for managing entities (yaya traits)
Validation is beautiful. We can validate data before it gets into an object and then validate the object state in a separate step.
It is easier for developers to understand what they are dealing with. You either have an object or an array of objects. An object can be linked to data which can also include other objects, but you no longer have to guess at what the array key will be, nor whether its nested funkily.
We can iterate on the interface for tables and entities separately. We couldn't easily change internals for the old Model class because of the implications on both, whereas now we can (in theory) change one without mucking about in the other.
It looks prettier simple.
Try this:
if ($this->request->is('post','put')) {
$data = $this->request->getData();
$comment = $this->Comments->newEntity();
$comment = $this->Comments->patchEntity($comment, $data);
$status = $this->Comments->save($comment);
if ($status) {
$this->Flash->success('comment submitted successfully.');
} else {
$this->Flash->error('Sorry, comment could not be updated.');
}
}
return $this->redirect($this->referer());
}
My advice is never use Post and Put in the same function. Just for good pratice. Put works fine when you make a update using id like a parameter.

Do Fluent conventions break lazy loading? (uNhAddIns)

I have a simple entity class in a WPF application that essentially looks like this:
public class Customer : MyBaseEntityClass
{
private IList<Order> _Orders;
public virtual IList<Order> Orders
{
get { return this._Orders; }
set {this._Orders = new ObservableCollection<Order>(value);}
}
}
I'm also using the Fluent automapper in an offline utility to create an NHibernate config file which is then loaded at runtime. This all works fine but there's an obvious performance hit due to the fact that I'm not passing the original collection back to NHibernate, so I'm trying to add a convention to get NHibernate to create the collection for me:
public class ObservableListConvention : ICollectionConvention
{
public void Apply(ICollectionInstance instance)
{
Type collectionType =
typeof(uNhAddIns.WPF.Collections.Types.ObservableListType<>)
.MakeGenericType(instance.ChildType);
instance.CollectionType(collectionType);
}
}
As you can see I'm using one of the uNhAddIns collections which I understand is supposed to provide support for both the convention and INotification changes, but for some reason doing this seems to break lazy-loading. If I load a custom record like this...
var result = this.Session.Get<Customer>(id);
...then the Orders field does get assigned an instance of type PersistentObservableGenericList but its EntityId and EntityName fields are null, and attempting to expand the orders results in the dreaded "illegal access to loading collection" message.
Can anyone tell me what I'm doing wrong and/or what I need to do to get this to work? Am I correct is assuming that the original proxy object (which normally contains the Customer ID needed to lazy-load the Orders member) is being replaced by the uNhAddIns collection item which isn't tracking the correct object?
UPDATE: I have created a test project demonstrating this issue, it doesn't reference the uNhAddins project directly but the collection classes have been added manually. It should be pretty straightforward how it works but basically it creates a database from the domain, adds a record with a child list and then tries to load it back into another session using the collection class as the implementation for the child list. An assert is thrown due to lazy-loading failing.
I FINALLY figured out the answer to this myself...the problem was due to my use of ObservableListType. In NHibernate semantics a list is an ordered collection of entities, if you want to use something for IList then you want an unordered collection i.e. a Bag.
The Eureka moment for me came after reading the answer to another StackOverflow question about this topic.

Using cached data from child window in parent window without a trip to the database

I'm looking for a design approach, so I don't have any code to share.
I have a WPF rich-client application that presents detail data to the user. When the user clicks "Edit" The entire form goes into edit state. This reveals a couple of "Add" buttons. These "Add" buttons open child views providing the user with tools to create new entities. Think "adding a new item to a customer order you're working with". That's the easy part.
When the user closes these child views, the new entities must be displayed and editable in the parent view for continued detailed editing. Something like "add the new item on the child form, pick the part number, then close the child and add quantity and delivery date on the parent view. I don't have any flexibility in this workflow. I have this working also.
When the user is finished with the parent view and is satisfied with the newly added items and detail edits they can click "Save". That is when all the changes need to go back to the database. If the user clicks cancel, all the changes including entities created on the child views must disappear, and the form returned to it's original state.
It's that last bit that stumps me. I'm almost new to Entity Framework, so I thought I could somehow keep the entire set of changes in memory on the client and commit all the changes to the database at the point of user-Save. I don't know if that's possible, or how I have to impliment my data changes to prevent accidental trips to the database.
To put all the facts on the table, I'm using a unit of work pattern, but I have access to an EF context object, if needed. If I have to work with the context object, I must do so across several views and their associated view-models.
I've looked at a whole lot of stackoverflow Q&A but cannot find, or perhaps recognize, a solution path. I've some ideas about using cloned entities, or perhaps transactions, but do not know if there are others or how to choose between them. These would be new skills and require time spent learning. I am willing to spend time learning a new skill, but not learning and trying three or four.
I'm grateful for any advice you might offer.
On the constructor when read from the DB record the value twice. One private variable for current and one for Old.
private string lNameOld;
private string lName;
public string LName
{
get { return lName; }
set
{
if(lName == value) return;
lName = value;
NotifyPropertyChanged("LName");
}
}
public void save()
{
if (lName != lNameOld)
{
// write to database
// really should process all in a transaction
lNameOld = lName;
}
{
public void cancel()
{
if (lName != lNameOld)
{
Lname = lNameOld; // notice capital L so Notify is called
}
{

Problem with checking an original database record with an edited one

I am having problems saving database records using Linq in visual studio 2010 and sql server 2008.
My problem is that when I am editing some records I sometimes check the original database record for validation purposes, only the original entry seems to be updated in real time - I.e. it is already exactly the same as the edited record, before I have submitted the changes!
Could anyone suggest an effective method of coping with this? I have tried using a 2nd database connection or a 2nd data repository to call the original record from the db but it appears to be already changed when I debug it.
public void SaveobjectEdit(object objectToEdit)
{
object originalObject = GetobjectById(objectToEdit.Id);
if (originalObject.objectStatus != objectToEdit.objectStatus)
{
originalObject.objectStatus = objectToEdit.objectStatus;
}
SaveChanges();
}
The save changes just calls _db.SubmitChanges(); by the way
Has no one got any ideas for the above question?
I hope I was clear - for validation purposes I would like to compare an original database record with one that I am editing. The problem is that when I edit a record and then attempt to retrieve the original record before saving - the original record is exactly the same as the edited record.
If you're trying to retrieve the original record in code, from the same 'context' using the same access method, then it will contain the updated object. Rather than ask why you're doing this or what you're trying to achieve, I'll instead explain how I understand the data context / object context to work (in a very loose and vague fashion).
The context is something like an in-memory representation of your database, where everything is lazy-loaded. When you instantiate the context you're given an object which represents your data model (of course it may not be a 1-1 representation, and can contain various abstractions). Nothing is loaded into the context until necessary; any queries you write stay as queries until you peer in their results. When you access an item (e.g. GetobjectById(objectToEdit.Id)) the item is loaded into the context from the database and you can get and set its properties at your leisure.
Now, the important part: When you access an item, if it has already been loaded into the context then that in-memory object is returned. The context doesn't care about checking changes made; the changes won't be persisted to the database until you submit, but they remain in memory.
The way to refresh the in-memory objects is to call the Refresh method on the context. Try this test:
using (var db = new MyObjectContext())
{
var item = db.Items.First();
item.Name = "testing this thing";
Console.WriteLine(db.Shifts.First().Name);
db.Refresh(System.Data.Objects.RefreshMode.StoreWins, db.Items);
Console.WriteLine(db.Shifts.First().Name);
}
I believe this pattern makes a lot of sense and I'm not sure it could work any other way. Consider this:
foreach (var item in db.Items)
{
item.Name = "test";
}
Assert(db.Items.All(item => item.Name == "test"));
Would you want the Assert to fail? Should those items be reloaded? I don't believe so. I'm looking at the items in my context, not in the database. I'm not checking whether items in the database have been updated, but instead that I've updated all the items in the context of my code.
This is a good reason why I don't use MyObjectContext db - it is not a 'db' or a database connection. It's a context within which I can change whatever I want, so I name it such: MyObjectContext context.

How to delete a column (attribute) from a GAE datastore?

I have a persistent class stored in a GAE datastore. I have removed one of the attributes from the class. The new records in this table show a value <none> for the removed attribute. But is there a way I can completely drop this column off the table?
Thanks.
Added the following 'migration' code according to moraes' suggestion, but it isn't achieving the desired result:
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
Query q = pm.newQuery(UserLogin.class);
Collection<UserLogin> list = (Collection<UserLogin>) q.execute();
Iterator<UserLogin> iter = list.iterator();
while (iter.hasNext()) {
UserLogin obj = (UserLogin) iter.next();
obj.setLoginDate(obj.getLoginDate());
}
pm.makePersistentAll(list);
} finally {
pm.close();
}
I found the answer to this problem in this Article:
http://code.google.com/appengine/articles/update_schema.html
"Removing Deleted Properties from the Datastore
If you remove a property from your model, you will find that existing entities still have the property. It will still be shown in the admin console and will still be present in the datastore. To really clean out the old data, you need to cycle through your entities and remove the data from each one.
Make sure you have removed the properties from the model definition.
If your model class inherits from db.Model, temporarily switch it to inherit from db.Expando. (db.Model instances can't be modified dynamically, which is what we need to do in the next step.)
Cycle through existing entities (like described above). For each entity, use delattr to delete the obsolete property and then save the entity.
If your model originally inherited from db.Model, don't forget to change it back after updating all the data."
And here is an example with code:
http://sandrylogan.wordpress.com/2010/12/08/delattr/
If you are using ndb (and you probably should), you can easily delete properties by deleting them from entity._properties:
for entity in MyModel.query():
if 'old_property' in entity._values:
del entity._properties['old_property']
del entity._values['old_property']
entity.put()
Or you could make it faster by using an asynchronous query map:
#ndb.tasklet
def cleanup(entity):
if 'old_property' in entity._values:
del entity._properties['old_property']
del entity._values['old_property']
yield entity.put_async()
MyModel.query().map(cleanup)
There is no concept of "table" in datastore. Each entity can have arbitrary properties that don't follow a common schema. The only "schema" is in your model code, and existing records don't change automatically when you change your models.
So, to delete the property from existing records, you need to iterate over all records and re-save them without the property.
The datastore viewer gets its list of columns from the datastore stats, which are updated on a regular basis. If you've removed that column from every entity that had it, wait a day or two and the datastore viewer will stop showing it.

Resources