How to update a Composition using Repository pattern? (An entity object cannot be referenced by multiple instances of IEntityChangeTracker.)


 hi everybody!

using vs2010,wcf ria services , ef. following general repository pattern implementation works fine (until now!)

public class repository<t> : irepository<t> t : class
    {
        objectcontext _context;
        iobjectset<t> _objectset;

        public repository(iconnectionstringprovider connectionstringprovider)
        {
            this._context = new iwebshopentities(connectionstringprovider.connectionstring);
            _context.contextoptions.lazyloadingenabled = true;
            _objectset = _context.createobjectset<t>();

        }

        public iqueryable<t> asqueryable()
        {
            return _objectset;
        }
        public ienumerable<t> getall()
        {
            return _objectset.tolist();

        }
        public ienumerable<t> find(expression<func<t, bool>> where)
        {
            return _objectset.where(where);
        }

        public objectcontext getcontext()
        {
            return _context;
        }
       
        public t single(expression<func<t, bool>> where)
        {
            return _objectset.single(where);
        }
        public t first(expression<func<t, bool>> where)
        {
            return _objectset.first(where);
        }
        public void delete(t entity)
        {
            _objectset.deleteobject(entity);
        }
        public void add(t entity)
        {
            _objectset.addobject(entity);
        }
        public void attach(t entity)
        {
            _objectset.attach(entity);
        }
        public void attachmodified(t entity)
        {
            _objectset.attach(entity);
            _context.objectstatemanager.changeobjectstate(entity, system.data.entitystate.modified);           
        }
        public void save()
        {
            _context.savechanges();

        }
    }

for creation of domain service 'm using  factory class:

 public class shopdomainservicefactory : idomainservicefactory, ihttpmodule
    {
        public domainservice createdomainservice(type domainservicetype, domainservicecontext context)
        {

            irepository<culture> culturerepository = servicelocator.current.getinstance<irepository<culture>>();
            irepository<currency> currencyrepository = servicelocator.current.getinstance<irepository<currency>>();
            irepository<customer> customerrepository = servicelocator.current.getinstance<irepository<customer>>();
            irepository<product> productrepository = servicelocator.current.getinstance<irepository<product>>();
            irepository<category> categoryrepository = servicelocator.current.getinstance<irepository<category>>();
            irepository<categorylocale> categorylocalerepository = servicelocator.current.getinstance<irepository<categorylocale>>();

            domainservice ds = (domainservice)activator.createinstance(domainservicetype
                , new object[] { culturerepository, currencyrepository, customerrepository, productrepository, categoryrepository, categorylocalerepository });

            ds.initialize(context);
            return ds;
        }

        public void releasedomainservice(domainservice domainservice)
        {
            domainservice.dispose();
        }

        #region ihttpmodule members

        public void dispose()
        {
            //throw new notimplementedexception();
        }

        public void init(httpapplication context)
        {
            domainservice.factory = this;
        }

        #endregion
    }

 

for example domain service methods category entities following (works fine):

 [linqtoentitiesdomainservicedescriptionprovider(typeof(iwebshopentities))]
    public partial class shopdomainservice : domainservice
    {
        [query]
        public virtual iqueryable<category> getallcategories()
        {
            return this.categoryrepository.getall().asqueryable();
        }

        [query]
        public virtual iqueryable<category> getcategoriesbyfilter(string xmlhttpencodedfiltercategory)
        {
            string xmlfiltercategory = httputility.urldecode(xmlhttpencodedfiltercategory);
            xmlserializer serializer = new xmlserializer(typeof(category));
            category filtercategory = (category)serializer.deserialize(xmlreader.create(new stringreader(xmlfiltercategory)));

            //the following lamda implements quering using filter attributes
            //every property and-ed next property
            expression<func<category, bool>> whereclause = c => (
                (!string.isnullorempty(filtercategory.name) ? c.name.contains(filtercategory.name) : true) &&
                (!string.isnullorempty(filtercategory.code) ? c.code.contains(filtercategory.code) : true) &&
                (!string.isnullorempty(filtercategory.seokeys) ? c.seokeys.contains(filtercategory.seokeys) : true) &&
                (!string.isnullorempty(filtercategory.seotitle) ? c.seotitle.contains(filtercategory.seotitle) : true) &&
                (filtercategory.categoryid > 0 ? c.categoryid == filtercategory.categoryid : true)
                );
            return this.categoryrepository.find(whereclause).asqueryable();
        }

        [query(iscomposable = false)]
        public category getcategory(int categoryid)
        {
            return this.categoryrepository.first(c => c.categoryid == categoryid);
        }

        [insert]
        public void insertcategory(category newcategory)
        {
            this.categoryrepository.add(newcategory);
            this.categoryrepository.save();
        }

        [update]
        public void updatecategory(category currentcategory)
        {
            this.categoryrepository.attachmodified(currentcategory);
            this.categoryrepository.save();
        }

        [delete]
        public void deletecategory(category currentcategory)
        {
            this.categoryrepository.attach(currentcategory);
            this.categoryrepository.delete(currentcategory);
            this.categoryrepository.save();
        }
    }

 

the domain service methods categorylocale defined identical:

 [linqtoentitiesdomainservicedescriptionprovider(typeof(iwebshopentities))]
    public partial class shopdomainservice : domainservice
    {
        [query]
        public virtual iqueryable<categorylocale> getallcategorylocales()
        {

            return this.categorylocalerepository.getall().asqueryable();
        }

        [query]
        public virtual iqueryable<categorylocale> getcategorylocalesbyfilter(string xmlhttpencodedfiltercategorylocale)
        {
            string xmlfiltercategorylocale = httputility.urldecode(xmlhttpencodedfiltercategorylocale);
            xmlserializer serializer = new xmlserializer(typeof(categorylocale));
            categorylocale filtercategorylocale = (categorylocale)serializer.deserialize(xmlreader.create(new stringreader(xmlfiltercategorylocale)));

            //the following lamda implements quering using filter attributes
            //every property and-ed next property
            expression<func<categorylocale, bool>> whereclause = c => (
                (!string.isnullorempty(filtercategorylocale.name) ? c.name.contains(filtercategorylocale.name) : true) &&
                (filtercategorylocale.categoryid > 0 ? c.categoryid == filtercategorylocale.categoryid : true)
                );
            return this.categorylocalerepository.find(whereclause).asqueryable();
        }

        [query(iscomposable = false)]
        public categorylocale getcategorylocale(int categorylocaleid)
        {
            return this.categorylocalerepository.first(c => c.categoryid == categorylocaleid);
        }


        [insert]
        public void insertcategorylocale(categorylocale newcategorylocale)
        {
            this.categorylocalerepository.add(newcategorylocale);
            this.categorylocalerepository.save();
        }

        [update]
        public void updatecategorylocale(categorylocale currentcategorylocale)
        {
            this.categorylocalerepository.attachmodified(currentcategorylocale);//<---------here error
            this.categorylocalerepository.save();
        }

        [delete]
        public void deletecategorylocale(categorylocale currentcategorylocale)
        {
            this.categorylocalerepository.attach(currentcategorylocale);
            this.categorylocalerepository.delete(currentcategorylocale);
            this.categorylocalerepository.save();
        }
    }

 the relationship between category , categorylocale 1:n (master-detail). include categorylocales of particular category , treat records whole used following definitions:

[metadatatype(typeof(category.categorymetadata))]
    public partial class category
    {
        internal sealed class categorymetadata
        {
            //to include category locale in queries
            [include]
            [composition]
            [association("categorylocales", "categoryid", "categoryid")]
            public objectset<categorylocale> categorylocales;
        }
    }

the problem this: every time change in categorylocale (detail) record following error:

message: unhandled error in silverlight application submit operation failed. entity object cannot referenced multiple instances of ientitychangetracker.

the code causes happen marked comment here error.

how avoid this?

thanks in advance!

you need make sure within scope of submit operation repositories make use of same instance of objectcontext.

basically should inject objectcontext repositories instead of trying create objectcontext in each repository.

there's createcontext method in linqtoentitiesdomainservice can override , after creating context pass repositories.

 



Silverlight  >  WCF RIA Services with Silverlight



Comments

Popular posts from this blog

Conditional formatting a graph vertical axis in SSRS 2012 charts

Register with Power BI failed

SQL server replication error Cannot find the dbo or user defined function........