New Posts New Posts RSS Feed: Possible Bug - Import entities
  FAQ FAQ  Forum Search   Calendar   Register Register  Login Login

Possible Bug - Import entities

 Post Reply Post Reply Page  123>
Author
smi-mark View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 24-Feb-2009
Location: Dallas, Texas
Posts: 343
Post Options Post Options   Quote smi-mark Quote  Post ReplyReply Direct Link To This Post Topic: Possible Bug - Import entities
    Posted: 30-Mar-2011 at 3:01pm
I'm using multiple EntityManagers in my app and I notice when I import an entity that has data changed, as long as it's not a navigation property, it updates fine so it's firing PropertyChanged. When I use a navigation property, it doesn't get fired properly.

It seems like the PropertyChanged for a navigation property is executed before it is changed.

If you need more info I can put a demo together.

Essentially:

This does not work:

                parent.Repository.ImportEntities(Repository.ExportEntities(EntityState.AnyAddedModifiedOrDeleted));

This does work:

                parent.Repository.ImportEntities(Repository.ExportEntities(EntityState.AnyAddedModifiedOrDeleted));
                parent.Repository.ImportEntities(Repository.ExportEntities(EntityState.AnyAddedModifiedOrDeleted));


Edited by smi-mark - 30-Mar-2011 at 3:10pm
Back to Top
smi-mark View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 24-Feb-2009
Location: Dallas, Texas
Posts: 343
Post Options Post Options   Quote smi-mark Quote  Post ReplyReply Direct Link To This Post Posted: 31-Mar-2011 at 6:41am
I found another issue, if an entity is in the Added state and has a Int32 primary key, it will add a new copy of the entity with a new auto generated key, rather than overwriting the existing one.

I haven't tested it with a guid yet, but I imagine it will work fine.


Edited by smi-mark - 31-Mar-2011 at 6:42am
Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 715
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 31-Mar-2011 at 12:28pm
Hi smi-mark;

Thanks for the info. I'm going to do a repro and file a bug report as necessary.
Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 715
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 31-Mar-2011 at 7:11pm
Hi smi-mark;

I was able to repro the issue with PropertyChanged, but unable to repro the one on your 2nd post about the Added state and Int32 primary key. Here's my repro.

    public void ImportingEntityWithIntPrimaryKey() {
      var mgr1 = new NorthwindIBEntityManager();
      var mgr2 = new NorthwindIBEntityManager();

      //Fetch entities
      var anOrderFromMgr1 = mgr1.Orders.FirstOrNullEntity();

      var aNewOrder2 = new Order();
      mgr2.AddEntity(aNewOrder2);
      aNewOrder2.OrderID = anOrderFromMgr1.OrderID;
      aNewOrder2.ShipCountry = "Italy";

      //Set Order to Added state
      anOrderFromMgr1.EntityAspect.SetAdded();

      //Import to mgr2
      mgr2.ImportEntities(new[] { anOrderFromMgr1 }, MergeStrategy.OverwriteChanges);

      var orders = mgr1.FindEntities<Order>(EntityState.AllButDetached);
      var count = orders.Count();
    }

The count is still 1 and aNewOrder2 was updated with all the values from anOrderFromMgr1. Please let me know what's different with your repro.
Back to Top
smi-mark View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 24-Feb-2009
Location: Dallas, Texas
Posts: 343
Post Options Post Options   Quote smi-mark Quote  Post ReplyReply Direct Link To This Post Posted: 31-Mar-2011 at 7:52pm
Hi Denis,

This how you can reproduce it:

var mgr1 = new TestEntities();
var mgr2 = new TestEntities();

var customer = mgr1.CreateEntity<Customer>();
customer.Name = "Test";

mgr1.AddEntity(customer);

mgr2.ImportEntities(mgr1.FindEntities<Customer>(EntityState.AllButDetached), MergeStrategy.OverwriteChanges);

Console.WriteLine("Mgr1 count {0} Mgr2 count {1}",
    mgr1.FindEntities<Customer>(EntityState.AllButDetached).Count(),
    mgr2.FindEntities<Customer>(EntityState.AllButDetached).Count());

mgr1.ImportEntities(mgr2.FindEntities<Customer>(EntityState.AllButDetached), MergeStrategy.OverwriteChanges);

Console.WriteLine("Mgr1 count {0} Mgr2 count {1}",
    mgr1.FindEntities<Customer>(EntityState.AllButDetached).Count(),
    mgr2.FindEntities<Customer>(EntityState.AllButDetached).Count());

foreach (var c in mgr1.FindEntities<Customer>(EntityState.AnyAddedModifiedOrDeleted))
{
    Console.WriteLine("{0} {1}", c.Id, c.Name);
}




You will see mgr1 now has the same entity twice, but with a different id


Edited by smi-mark - 31-Mar-2011 at 7:59pm
Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 715
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 01-Apr-2011 at 10:01am
Thanks smi-mark.
Back to Top
smi-mark View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 24-Feb-2009
Location: Dallas, Texas
Posts: 343
Post Options Post Options   Quote smi-mark Quote  Post ReplyReply Direct Link To This Post Posted: 01-Apr-2011 at 3:51pm
I have found a workaround for both problems.

For the first problem, as above, I just call it twice.

For the second problem, I do it like this:

        public static void ImportFrom(this EntityManager manager, EntityManager fromManager)
        {
            var addedEntities = fromManager.FindEntities(EntityState.Added).OfType<Entity>().ToList();
            fromManager.RemoveEntities(addedEntities);
            manager.ImportEntities(fromManager.FindEntities(EntityState.AllButDetached), MergeStrategy.OverwriteChanges);
            manager.AddEntities(addedEntities);
        }


Edited by smi-mark - 01-Apr-2011 at 4:16pm
Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 715
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 01-Apr-2011 at 4:38pm
Thanks again smi-mark. This is really helpful.
Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 715
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 19-Apr-2011 at 1:08pm
Hi smi-mark;

I've discussed the issue regarding importing entity with an Added state and temp id resulting in a duplicate entity with the lead developer and confirmed that this is the correct behavior.

The reason is that, when the entity is still in the Added state and has a temp id, EntityManager still considers it as a new entity and so when another same entity with the same temp id is also imported, EM will consider that entity a "new" entity and assigns it a new temp id.

The workaround by setting that entity to Modified, (calling AcceptChanges will work as well), is correct because we're telling the EntityManager that the entity is no longer new as we have "touched" it.

Please let me know if you still have further questions. I will post more updates on the PropertyChanged issue when I have some.


Edited by DenisK - 19-Apr-2011 at 1:10pm
Back to Top
smi-mark View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 24-Feb-2009
Location: Dallas, Texas
Posts: 343
Post Options Post Options   Quote smi-mark Quote  Post ReplyReply Direct Link To This Post Posted: 19-Apr-2011 at 1:33pm
Hi Denis,

I need to test this, but in a "modified" state, won't they try to update in the database rather than inserting them? These are new entities that have not yet been saved.

This is being used in a sandbox scenario such as this:

Customer - EM 1
      Customer Address Edit - EM 2

When EM 2 "saves" it does not really save, it simply merges back into EM 1. EM 1 is responsible for saving of any changes.

I am doing it like this to simulate the old checkpointing ability in DevForce classic.
Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 715
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 20-Apr-2011 at 1:53pm
Hi smi-mark;

If the new "modified" entity still has a temp id, upon call to SaveChanges, EntityManager will do an id fixup and insert that new entity into the database. It will not update an existing entity in the database.

As I've mentioned before, you could also call AcceptChanges on CustomerAddress before EM2 saves/merges the entity back into EM1. I believe this will work better since you can call RejectChanges to roll back any Modified entity back to its Unchanged state.
Back to Top
smi-mark View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 24-Feb-2009
Location: Dallas, Texas
Posts: 343
Post Options Post Options   Quote smi-mark Quote  Post ReplyReply Direct Link To This Post Posted: 20-Apr-2011 at 3:46pm
Hi Denis,

Perfect, if that is the case then that will work fine.

Thanks for looking into it.
Back to Top
smi-mark View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 24-Feb-2009
Location: Dallas, Texas
Posts: 343
Post Options Post Options   Quote smi-mark Quote  Post ReplyReply Direct Link To This Post Posted: 22-Apr-2011 at 11:20am
Hi Denis,

Using AcceptChanges or SetModified by it self didn't work, but I do seem to have a solution:

I create a list of entities from EM2 with a state of Added, call AcceptChanges, import to EM1

For each Added Entity in EM2 i find the Entity using FindEntity EntityKey in EM1 and call SetAdded on it, this keeps the temporary Id and seems to work.


var addedEntities = fromManager.FindEntities(EntityState.Added)
                .OfType<Entity>()
                .ToList();
 
addedEntities.ForEach(e => e.EntityAspect.AcceptChanges());
toManager.ImportEntities(addedEntities, MergeStrategy.OverwriteChanges);
 
addedEntities.Select(entity => toManager.FindEntity(entity.EntityAspect.EntityKey) as Entity)
              .ForEach(e => e.EntityAspect.SetAdded());




Edited by smi-mark - 22-Apr-2011 at 11:21am
Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 715
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 25-Apr-2011 at 11:48am
Thanks for sharing your solution smi-mark. 

Could you clarify what you meant by "Using AcceptChanges or SetModified by it self didn't work" ?

What do you mean by itself and what didn't work?
Back to Top
DenisK View Drop Down
IdeaBlade
IdeaBlade


Joined: 25-Aug-2010
Posts: 715
Post Options Post Options   Quote DenisK Quote  Post ReplyReply Direct Link To This Post Posted: 11-May-2011 at 12:36pm
Hi smi-mark;

I just want to follow up again on this to make sure that there isn't any other bug. 

The code snippet in your last post seems to be similar to what I'm doing in my testing but I'm still having a hard time understanding when you said ""Using AcceptChanges or SetModified by it self didn't work".

I would appreciate it if you can clarify that to me so I know all the bugs related to this that could be discovered are discovered.

Thanks!
Back to Top
smi-mark View Drop Down
DevForce MVP
DevForce MVP
Avatar

Joined: 24-Feb-2009
Location: Dallas, Texas
Posts: 343
Post Options Post Options   Quote smi-mark Quote  Post ReplyReply Direct Link To This Post Posted: 11-May-2011 at 12:45pm
Hi Denis,

I have had to work on a couple other projects recently, I will get back to this and create an example showing what I mean.

Thanks,

Mark
Back to Top
 Post Reply Post Reply Page  123>

Forum Jump Forum Permissions View Drop Down