Altinet
  • Home
  • Blog
  • Contact





Associations and insert ordering

On 21 Mar, 2011
Uncategorized
By : Bruno Samardzic
No Comments
Views : 5675

Well, i ran into an issue while inserting multiple records which is nicely described in my post on a forum:

http://forums.silverlight.net/forums/t/222783.aspx

Long story short, ria services doesn’t take care of the ordering of the items when calling insert methods for entities, ie it could easily call insert on child before parent. This problem doesn’t show itself when using Composition attribute, but it’s not like you want to use that attribute every time, so if you’re not using you’re pretty much leaving yourself at the mercy of your ORM. And Nhibernate is pretty crude sometimes in some respects, one of them being the data insertion.
If you don’t explicitly establish 2-way connection, NHibernate is just going to insert the data in the order you persisted it. Which in combination with RIA Service’s indifference is BAD.
I won’t give any sample project because it’s a bit difficult to extract plus i don’t have time, but this is the basic principle.
I decided to make a workaround on the Service level. What i decided to do is make an override on domainservice’s Submit method.

        public override bool Submit(ChangeSet changeSet)
        {
            InsertList = changeSet.ChangeSetEntries
                .Where(x => x.Operation == DomainOperation.Insert && x.Entity is BaseEditModel)
                .Select(y => new InsertEntry(false, y)).ToList();

            foreach (var entry in InsertList)
            {
                if (!entry.Inserted)
                {
                    PersistEntry(entry, InsertList);
                }
            }
            return base.Submit(changeSet);
        }

BaseEditModel is a base class i use for all the Presentation models, you should use your own base clas, the point is that you just take entites which are getting inserted.
InsertEntry class is pretty basic:

        private class InsertEntry
        {
            public InsertEntry(bool inserted, ChangeSetEntry entry)
            {
                Inserted = inserted;
                Entry = entry;
            }

            public ChangeSetEntry Entry { get; set; }

            public bool Inserted { get; set; }

        }

It’s used basically for keeping track of already persisted entities.
The meat of the solution is in the PersistEntry method:

        private void PersistEntry(InsertEntry insEntry, IEnumerable<InsertEntry> insertList)
        {
            if (insEntry.Inserted) return;
            var entPm = (BaseEditModel)insEntry.Entry.Entity;
            if (entPm == null) return;
            if (insEntry.Entry.Associations != null)
//iterate through associations of the entry
                foreach (var ass in insEntry.Entry.Associations)
                {
//test if the association is a foreign key association
                    if (IsForeignKey(entPm.GetType(), ass.Key))
                    {
//find the entity from association in the insertList
                        var entryTup = insertList.FirstOrDefault(x => x.Entry.Id == ass.Value[0]);
//if it's found and it's not already inserted, insert it
                        if (entryTup != null && !entryTup.Inserted)
//the insertion is done recursively 
                            PersistEntry(entryTup, insertList);
                    }
                }
//since i'm using the presentation model, i first have to find the corresponding domain entity model
            var entType = GetEntType(entPm);
            var ent = (BaseEntity)Activator.CreateInstance(entType);
            ent.Guid = entPm.Guid;
//sets the entity properties from presentation model
            entPm.SetEntity(ent, this);
//and finally persist it
            Repository.Persist(ent);
//set the inserted property to true so that the same entity doesn't get inserted 2 times
            insEntry.Inserted = true;
        }

The IsForeignKey method basically tests the association of a property for foreignkey bool value

        private static bool IsForeignKey(Type entPmType, string propName)
        {
            var propInfo = entPmType.GetProperties().FirstOrDefault(x => x.Name == propName);
            if (propInfo == null) return false;
            var assAtt = propInfo.GetCustomAttributes(typeof(AssociationAttribute), false)[0] as AssociationAttribute;
            return assAtt != null && assAtt.IsForeignKey;
        }

I documented the code the best i could, so i hope you get the picture. The only thing left to do is to modify the InsertEntity methods so that it doesn’t persist anything, because we already persisted it.

        protected void InsertEntity(TPm entityPm)
        {
            var entity = Repository.GetItem(entityPm.Guid);
            ChangeSet.Associate(entityPm, entity, UpdateEntityPmAttributes);
        }

So the previous method is used mostly to do the Association, we already did the persistion stuff in the submit method.
And that’s basically it, we did the insertion in the order which respects associations, and therefore you don’t get those nasty foreign key sql exceptions. Hope it’s well explained and you’ll find the way to use it on your example. It can easily be used on Entity domain models too.
Hope this helps!



Previous Post Next Post 

About The Author

Bruno Samardzic


Number of Posts : 45
All Posts by : Bruno Samardzic

Leave a Comment

Click here to cancel reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>





Recent Posts

  • Angular vs React: round 2
  • Why programming is hard
  • Orchard Workflows, undocumented gem
  • The React Redux
  • React.js invoicing CRUD application, part 2: Description

Recent Comments

  • Angshuman on Animation for starred grid rows and columns using xaml
  • Advanced Excel Training in Lucknow on Angular vs React: round 2
  • Reginald Sophomore on My example of Angularjs directive
  • Slobodan on Angular and Breeze – story so far.
  • Bruno Samardzic on Reaction to Ember-forged Durandal Angularly Knocking out my Backbone, or my JS MVC framework research conclusion.

Contact

Altinet d.o.o.

OIB: 97429091194

Čulinečka cesta 146, Zagreb

Tel: +385 (1) 2946 819

Mob: +385 (98) 210 756

IBAN: HR4323400091110406470

Latest tweets