Tim Mallalieu's Blog.

Just a PM's random musings on data, models, services...

Databinding with ADO.NET Entity Framework

Databinding with ADO.NET Entity Framework

  • Comments 5

So,

 

I am a self-admitted “value layer” bigot. I spend a lot of my coding time in ADO.NET Entities building stuff on top of our value layer (in other words working directly against Entity Client without using our object abstractions). Recently however I have been having a lot of fun writing apps at the Object Layer. One thing that I found I needed to do to make my life easier is have a more general purpose data binding solution until we have our production data binding support in place. For what it’s worth our next CTP should have data binding in place so my post today should not be relevant after that.

 

Anyway… I decided that what I would do is derive from BindingList<T> and have a trivial binding list implementation that was aware of our Entities and our ObjectContext to make my life a little easier… not much code but here goes:

 

    /// <summary>

    /// Trivial extension of BindingList<T> for working with Entities

    /// </summary>   

    public class EntityBindingList<T> : BindingList<T> where T : Entity

    {

        /// <summary>

        /// reference an ObjectContext so that we can do saves

        /// </summary>

        private ObjectContext context;

 

 

        /// <summary>

        /// Constructor that takes an ObejctContext as an argument

        /// </summary>

        /// <param name="context">The current ObejctContext being used to interact with the persistent entities</param>

        public EntityBindingList(ObjectContext context)

            : base()

        {

            this.context = context;

        }

 

 

        /// <summary>

        /// Remove an item from the list, if the item is already attached to

        /// the object context call DeleteObject so that when we save the context

        /// this object is deleted from the store, if it is in the Detached state

        /// just remove it from the list.

        /// </summary>

        /// <param name="index"></param>

        protected override void RemoveItem(int index)

        {

 

            Entity itemToRemove = this.Items[index];

            if (itemToRemove.EntityState != EntityState.Detached)

            {

                context.DeleteObject(itemToRemove);

            }

            base.RemoveItem(index);

        }

      

        /// <summary>

        /// A save changes method that allows one

        /// to save the changes in the list to the underlying

        /// store.

        /// The assumption is that entities that have been retrieved

        /// from the store were retrieved in a mode that stores them

        /// in the state manager and that they are being change-tracked.

        /// As a result, all we need to do is add any detached entities (new rows)

        /// to the context and then invoke save changes.       

        /// </summary>

        public void SaveChanges()

        {

            foreach (Entity entity in this.Items)

            {

                if (EntityState.Detached == entity.EntityState)

                {

                    context.AddObject(entity);

                }

 

            }

            context.SaveChanges();

        }

       

        /// <summary>

        /// Helper method for loading a binding list from an IEnumerable<T>

        /// T for this class is constrained to be an Entity or specialization       

        /// </summary>

        /// <param name="entities">The entities we want loaded into the binding liste</param>

        public void Load(IEnumerable<T> entities)

        {

            foreach (T entity in entities)

            {

                this.Add(entity);

            }

        }

 

    }

 

With this class I can now use object data sources with little additional coding… for example consider the following code:

                               

//--- create a new EntityBindinglist passing it the instance of our object context (in this case model)

            this.customers = new EntityBindingList<Customer>(model);

           

//--- Populate the binding list by executing the Customers query (a property on my generated object context)

//--- Note that when I execute I use the MergeOption “AppendOnly” I have a new context instance and

//--- want to add the retrieved instances to the state manager for state tracking and identity resolution

            this.customers.Load(model.Customers.Execute(MergeOption.AppendOnly));

           

//--- set the datasource property of my CustomersBindingSource to my new binding list

            this.CustomersBindingSrc.DataSource = customers;

 

To save the changes by wiring up “save” functionality from a binding navigator I provide a save event handler for the save button:

 

                      private void saveToolStripButton_Click(object sender, EventArgs e)

        {

            this.customers.SaveChanges();

        }

 

That’s about it…               

Leave a Comment
  • Please add 7 and 3 and type the answer here:
  • Post
  • The blue color font is a bit tough to see againt the black background.

  • public void SaveChanges()

           {

               foreach (Entity entity in this.Items)

               {

                   if (DataRowState.Detached == entity.EntityState)

                   {

                       context.AddObject(entity);

                   }

               }

               context.SaveChanges();

           }

    Note i've changed Entity.Detached by DataRowState.Detached since in my bits, that is the type of EntityState (for an entity)

    So far it runs this way, testing this :D

    I'm missing something here? I'm very new to ADO.Net vNext

  • ObjectContext.AddObject(entity) is no longer supported (?). The is another overload

    ObjectContext.AddObject("entitySetName", entity)

    How do I find out the correct EntitySet name having just generic Entity type (T) available?

  • ObjectContext.AddObject(entity) is no longer supported (?). The is another overload

    ObjectContext.AddObject("entitySetName", entity)

    How do I find out the correct EntitySet name having just generic Entity type (T) available?

  • I have been able to successfully implement a custom binding list entity such as your example.  I cannot however, get this to work in a situation where I have nested binding source objects on a winform in order to achieve master-detail binding.  How would one inject in to ObjectQuery<TEntity> or EntityCollection<T> to override the IListSource interface so that the GetList() member of IListSource could return my custom EntityBindingList<TEntity>?

Page 1 of 1 (5 items)