MVC/LinqtoSql - Editing an EntitySet<T> collection creates new id

Discussion in 'ASP .Net' started by RichB, Jun 5, 2009.

  1. RichB

    RichB Guest

    I posted a previous question regarding creation of Collections in LinqtoSql
    and a premature question related to editing objects. I thought that I had
    managed to sort it out, but unfortunately I haven't.

    It may be useful to look at the following post as it was my stating point
    and provides a solution which I have implemented:

    http://www.microsoft.com/communitie...40bca7c0&lang=en&cr=US&sloc=en-us&m=1&p=1#top


    This solution works perfectly for creating records, however when it comes to
    updating those records the behavior is strange and I cannot work out why.

    I am using Linq2Sql to generate the model returned by a repository pattern
    (repo.Get(id)). That Venue repository contains within it's structure the
    EntitySet<ContactData> _contactDatas as a variable within a ContactList.

    I have two cases both use a database table (ContactData) with an id column
    and a fk to the id column of another table (ContactList) thereby giving a
    ContactList = 1 to ContactData = many relationship:

    Example 1- my demo project
    ContactData id column is of type int IDENTITY. The FK to ContactList Allows
    Nulls (for example only)

    Example 2 - my actual project
    ContactData id column is of type uniqueinteger, is a RowGuid and has a
    default value = newid(). The FK to ContactList does not allow nulls. Within
    Linq2Sql designer AutoGenerated Value = true.


    My Controller code to handle a edit post is as follows:

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Edit(int id, FormCollection formValues)
    {
    Venue venue = repo.GetVenue(id);
    UpdateModel(venue, "Venue", formValues.ToValueProvider());
    repo.Save();

    Trace.WriteLine(venue.VenueDetail.ContactLink.ContactDatas.ToString());
    //However it is not populated with objects

    Trace.WriteLine(venue.VenueDetail.ContactLink.ContactDatas[0].ToString());
    return RedirectToAction("Edit", new { id = venue.VenueId });
    }

    For Example 1:
    When I load the venue with the model data I have a ContactData object within
    the ContactList. If I then step into the UpdateModel(...) method the venue is
    updated with data from the formvalues collection. If I update a Property
    (e.g.) venue.Title, then an update is performed and the venue.Id remains
    unchanged. WIhin the ContactData objects, whether I update the value or not
    the ContactData.Id is set to 0 by the UpdateModel(...) method, and the
    resultant db table contains the old record with the FK set to null and a new
    record for the updated values.

    In Example 2
    The behaviour is similar, although even though the ContactData.Id
    Autogenerated value is true the UpdateModel assigned value is
    00000000-0000-0000-0000-000000000000 rather than the existing key. Then when
    the UpdateModel(..) method is run I get an InvalidOperationException: An
    attempt was made to remove a relationship between a ContactLink and a
    ContactData. However, one of the relationship's foreign keys
    (ContactData.ContactLinkID) cannot be set to null.

    This seems to me very strange behaviour which I am really struggling to
    understand. I can supply my example 1 as a demo if required, but would
    appreciate any pointers on how to solve this.
    RichB, Jun 5, 2009
    #1
    1. Advertising

  2. Hi,

    >This seems to me very strange behaviour which I am really struggling to
    >understand. I can supply my example 1 as a demo if required, but would
    >appreciate any pointers on how to solve this.


    From your description the problem is a bit complicated. It's hard for me to
    say anything before debugging your code. Could you send that demo and the
    database file (please replace sensitive data with test data) to me? My
    email is se update here after sending the project
    in case I missed that email.

    Regards,
    Allen Chen
    Microsoft Online Support

    Delighting our customers is our #1 priority. We welcome your comments and
    suggestions about how we can improve the support we provide to you. Please
    feel free to let my manager know what you think of the level of service
    provided. You can send feedback directly to my manager at:
    .

    ==================================================
    Get notification to my posts through email? Please refer to
    http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

    Note: MSDN Managed Newsgroup support offering is for non-urgent issues
    where an initial response from the community or a Microsoft Support
    Engineer within 2 business day is acceptable. Please note that each follow
    up response may take approximately 2 business days as the support
    professional working with you may need further investigation to reach the
    most efficient resolution. The offering is not appropriate for situations
    that require urgent, real-time or phone-based interactions. Issues of this
    nature are best handled working with a dedicated Microsoft Support Engineer
    by contacting Microsoft Customer Support Services (CSS) at
    http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
    ==================================================
    This posting is provided "AS IS" with no warranties, and confers no rights.
    Allen Chen [MSFT], Jun 8, 2009
    #2
    1. Advertising

  3. RichB

    RichB Guest

    Allen,

    I have sent you the demo app.

    Thanks,
    Richard

    "RichB" <> wrote in message
    news:...
    >
    >
    > I posted a previous question regarding creation of Collections in
    > LinqtoSql
    > and a premature question related to editing objects. I thought that I had
    > managed to sort it out, but unfortunately I haven't.
    >
    > It may be useful to look at the following post as it was my stating point
    > and provides a solution which I have implemented:
    >
    > http://www.microsoft.com/communitie...40bca7c0&lang=en&cr=US&sloc=en-us&m=1&p=1#top
    >
    >
    > This solution works perfectly for creating records, however when it comes
    > to
    > updating those records the behavior is strange and I cannot work out why.
    >
    > I am using Linq2Sql to generate the model returned by a repository pattern
    > (repo.Get(id)). That Venue repository contains within it's structure the
    > EntitySet<ContactData> _contactDatas as a variable within a ContactList.
    >
    > I have two cases both use a database table (ContactData) with an id column
    > and a fk to the id column of another table (ContactList) thereby giving a
    > ContactList = 1 to ContactData = many relationship:
    >
    > Example 1- my demo project
    > ContactData id column is of type int IDENTITY. The FK to ContactList
    > Allows
    > Nulls (for example only)
    >
    > Example 2 - my actual project
    > ContactData id column is of type uniqueinteger, is a RowGuid and has a
    > default value = newid(). The FK to ContactList does not allow nulls.
    > Within
    > Linq2Sql designer AutoGenerated Value = true.
    >
    >
    > My Controller code to handle a edit post is as follows:
    >
    > [AcceptVerbs(HttpVerbs.Post)]
    > public ActionResult Edit(int id, FormCollection formValues)
    > {
    > Venue venue = repo.GetVenue(id);
    > UpdateModel(venue, "Venue", formValues.ToValueProvider());
    > repo.Save();
    >
    > Trace.WriteLine(venue.VenueDetail.ContactLink.ContactDatas.ToString());
    > //However it is not populated with objects
    >
    > Trace.WriteLine(venue.VenueDetail.ContactLink.ContactDatas[0].ToString());
    > return RedirectToAction("Edit", new { id = venue.VenueId });
    > }
    >
    > For Example 1:
    > When I load the venue with the model data I have a ContactData object
    > within
    > the ContactList. If I then step into the UpdateModel(...) method the venue
    > is
    > updated with data from the formvalues collection. If I update a Property
    > (e.g.) venue.Title, then an update is performed and the venue.Id remains
    > unchanged. WIhin the ContactData objects, whether I update the value or
    > not
    > the ContactData.Id is set to 0 by the UpdateModel(...) method, and the
    > resultant db table contains the old record with the FK set to null and a
    > new
    > record for the updated values.
    >
    > In Example 2
    > The behaviour is similar, although even though the ContactData.Id
    > Autogenerated value is true the UpdateModel assigned value is
    > 00000000-0000-0000-0000-000000000000 rather than the existing key. Then
    > when
    > the UpdateModel(..) method is run I get an InvalidOperationException: An
    > attempt was made to remove a relationship between a ContactLink and a
    > ContactData. However, one of the relationship's foreign keys
    > (ContactData.ContactLinkID) cannot be set to null.
    >
    > This seems to me very strange behaviour which I am really struggling to
    > understand. I can supply my example 1 as a demo if required, but would
    > appreciate any pointers on how to solve this.
    >
    >
    >
    >
    RichB, Jun 8, 2009
    #3
  4. Hi Richard,

    Thanks for your project.

    >For Example 1:
    >When I load the venue with the model data I have a ContactData object

    within
    >the ContactList. If I then step into the UpdateModel(...) method the venue

    is
    >updated with data from the formvalues collection. If I update a Property
    >(e.g.) venue.Title, then an update is performed and the venue.Id remains
    >unchanged. WIhin the ContactData objects, whether I update the value or

    not
    >the ContactData.Id is set to 0 by the UpdateModel(...) method, and the
    >resultant db table contains the o


    I've investigated this issue. The cause is as below:

    First test this:

    If you test the following code the record will be updated as normal:

    Venue venue = repo.GetVenue(5);
    venue.VenueDetail.ContactLink.ContactDatas[0].Data
    =DateTime.Now.Millisecond.ToString() ;

    repo.Save();


    However, the following code does not work (it result in the same behavior
    as you described):

    Venue venue = repo.GetVenue(5);

    venue.VenueDetail.ContactLink.ContactDatas[0]=
    new ContactData()
    {
    Data = DateTime.Now.Millisecond.ToString()
    }
    ;


    repo.Save();

    Linq to SQL sees there's a new ContactData so it will insert a new one.
    Till now it's pure Linq to SQL issue.

    Now back to your case. The cause is, the UpdateModel method internally will
    create a new instance for collection item. Therefore it result in the
    behavior you described. You can confirm it by this way:

    1. Set breakpoint at this line:

    UpdateModel(venue, "Venue", formValues.ToValueProvider());

    and check venue.VenueDetail.ContactLink.ContactDatas[0].GetHashCode()

    2. In the folloiwng code set breakpoint following the comment in it:

    public EntitySet<ContactData> ContactDatas
    {
    get
    {
    return this._ContactDatas;
    }
    set
    {
    //set a breakpoint here to check this._ContactDatas[0].GetHashCode()

    if(this._ContactDatas!=value)//this is updated workaround for
    your another case. It will not manually involve new instance when updating.
    But it still doesn't help to solve the problem you mentioned in this case
    this._ContactDatas.Assign(value);
    }
    }

    3. The result is they are different object.


    To workaround it you probably can manually assign data like the first code
    sneppet in this post.

    Venue venue = new Venue();

    UpdateModel(venue, "Venue", formValues.ToValueProvider());

    Venue venue2 = repo.GetVenue(id);

    //Now you've got all data needed. Assign what need to update from venue to
    venue2.

    Regards,
    Allen Chen
    Microsoft Online Support

    Delighting our customers is our #1 priority. We welcome your comments and
    suggestions about how we can improve the support we provide to you. Please
    feel free to let my manager know what you think of the level of service
    provided. You can send feedback directly to my manager at:
    .

    ==================================================
    Get notification to my posts through email? Please refer to
    http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.

    Note: MSDN Managed Newsgroup support offering is for non-urgent issues
    where an initial response from the community or a Microsoft Support
    Engineer within 2 business day is acceptable. Please note that each follow
    up response may take approximately 2 business days as the support
    professional working with you may need further investigation to reach the
    most efficient resolution. The offering is not appropriate for situations
    that require urgent, real-time or phone-based interactions. Issues of this
    nature are best handled working with a dedicated Microsoft Support Engineer
    by contacting Microsoft Customer Support Services (CSS) at
    http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
    ==================================================
    This posting is provided "AS IS" with no warranties, and confers no rights.
    Allen Chen [MSFT], Jun 9, 2009
    #4
  5. RichB

    RichB Guest

    Thanks Allen,

    It would seem that the behaviour of Update model is not working in an
    optimum way, i.e. it is not doing a true update of the model as it is
    creating this new instance (and only apparently for EntitySets). Should this
    be reported as an issue within ASP.Net MVC, and if so where should I go to
    report that?

    Your solution to Assign what is needed from the Model object to the repo
    object is easily said, but in practice what is the best way to do this, is
    there a way to iterate through all of the Properties in the model object and
    assign them to the corresponding Property in the corresponding repository
    object? Also can I guarantee that the objects at each index are the
    corresponding object (i.e. venue..ContactDatas[0].Data and
    venue2.ContactDatas[0].Data are the original and updated objects) ?

    Thanks,
    Richard




    "Allen Chen [MSFT]" <> wrote in message
    news:...
    > Hi Richard,
    >
    > Thanks for your project.
    >
    >>For Example 1:
    >>When I load the venue with the model data I have a ContactData object

    > within
    >>the ContactList. If I then step into the UpdateModel(...) method the venue

    > is
    >>updated with data from the formvalues collection. If I update a Property
    >>(e.g.) venue.Title, then an update is performed and the venue.Id remains
    >>unchanged. WIhin the ContactData objects, whether I update the value or

    > not
    >>the ContactData.Id is set to 0 by the UpdateModel(...) method, and the
    >>resultant db table contains the o

    >
    > I've investigated this issue. The cause is as below:
    >
    > First test this:
    >
    > If you test the following code the record will be updated as normal:
    >
    > Venue venue = repo.GetVenue(5);
    > venue.VenueDetail.ContactLink.ContactDatas[0].Data
    > =DateTime.Now.Millisecond.ToString() ;
    >
    > repo.Save();
    >
    >
    > However, the following code does not work (it result in the same behavior
    > as you described):
    >
    > Venue venue = repo.GetVenue(5);
    >
    > venue.VenueDetail.ContactLink.ContactDatas[0]=
    > new ContactData()
    > {
    > Data = DateTime.Now.Millisecond.ToString()
    > }
    > ;
    >
    >
    > repo.Save();
    >
    > Linq to SQL sees there's a new ContactData so it will insert a new one.
    > Till now it's pure Linq to SQL issue.
    >
    > Now back to your case. The cause is, the UpdateModel method internally
    > will
    > create a new instance for collection item. Therefore it result in the
    > behavior you described. You can confirm it by this way:
    >
    > 1. Set breakpoint at this line:
    >
    > UpdateModel(venue, "Venue", formValues.ToValueProvider());
    >
    > and check venue.VenueDetail.ContactLink.ContactDatas[0].GetHashCode()
    >
    > 2. In the folloiwng code set breakpoint following the comment in it:
    >
    > public EntitySet<ContactData> ContactDatas
    > {
    > get
    > {
    > return this._ContactDatas;
    > }
    > set
    > {
    > //set a breakpoint here to check this._ContactDatas[0].GetHashCode()
    >
    > if(this._ContactDatas!=value)//this is updated workaround for
    > your another case. It will not manually involve new instance when
    > updating.
    > But it still doesn't help to solve the problem you mentioned in this case
    > this._ContactDatas.Assign(value);
    > }
    > }
    >
    > 3. The result is they are different object.
    >
    >
    > To workaround it you probably can manually assign data like the first code
    > sneppet in this post.
    >
    > Venue venue = new Venue();
    >
    > UpdateModel(venue, "Venue", formValues.ToValueProvider());
    >
    > Venue venue2 = repo.GetVenue(id);
    >
    > //Now you've got all data needed. Assign what need to update from venue to
    > venue2.
    >
    > Regards,
    > Allen Chen
    > Microsoft Online Support
    >
    > Delighting our customers is our #1 priority. We welcome your comments and
    > suggestions about how we can improve the support we provide to you. Please
    > feel free to let my manager know what you think of the level of service
    > provided. You can send feedback directly to my manager at:
    > .
    >
    > ==================================================
    > Get notification to my posts through email? Please refer to
    > http://msdn.microsoft.com/en-us/subscriptions/aa948868.aspx#notifications.
    >
    > Note: MSDN Managed Newsgroup support offering is for non-urgent issues
    > where an initial response from the community or a Microsoft Support
    > Engineer within 2 business day is acceptable. Please note that each follow
    > up response may take approximately 2 business days as the support
    > professional working with you may need further investigation to reach the
    > most efficient resolution. The offering is not appropriate for situations
    > that require urgent, real-time or phone-based interactions. Issues of this
    > nature are best handled working with a dedicated Microsoft Support
    > Engineer
    > by contacting Microsoft Customer Support Services (CSS) at
    > http://msdn.microsoft.com/en-us/subscriptions/aa948874.aspx
    > ==================================================
    > This posting is provided "AS IS" with no warranties, and confers no
    > rights.
    >
    >
    >
    >
    RichB, Jun 9, 2009
    #5
  6. Hi Richard,

    >It would seem that the behaviour of Update model is not working in an
    >optimum way, i.e. it is not doing a true update of the model as it is
    >creating this new instance (and only apparently for EntitySets). Should

    this
    >be reported as an issue within ASP.Net MVC, and if so where should I go to
    >report that?


    Yes I agree. It looks like either the UpdateModel or the Linq to Sql
    SubmitChanges method needs improvement. You can submit a feedback via our
    connect site for further investigation:

    https://connect.microsoft.com/VisualStudio/Feedback

    >Your solution to Assign what is needed from the Model object to the repo
    >object is easily said, but in practice what is the best way to do this, is
    >there a way to iterate through all of the Properties in the model object

    and
    >assign them to the corresponding Property in the corresponding repository
    >object?


    If you need a generic method you can write a helper method that uses
    reflection to copy data. Use obj.GetType().GetProperties() to get all
    properties of obj and use following way to get/set value:

    http://msdn.microsoft.com/en-us/library/b05d59ty.aspx
    http://msdn.microsoft.com/en-us/library/aa330197(VS.71).aspx


    >Also can I guarantee that the objects at each index are the
    >corresponding object (i.e. venue..ContactDatas[0].Data and
    >venue2.ContactDatas[0].Data are the original and updated objects) ?


    Object got by repo.GetVenue(id) is the original record. Object got by the
    following way is the updated record.

    Venue venue = new Venue();
    UpdateModel(venue, "Venue", formValues.ToValueProvider());



    Regards,
    Allen Chen
    Microsoft Online Support
    Allen Chen [MSFT], Jun 10, 2009
    #6
  7. RichB

    RichB Guest

    Thanks Allen,

    I have raised a bug on the connect site, and hope that it can be solved. In
    doing this I was interested to note that the previous issue is resolved and
    scheduled for release in .NET framework 4.0.

    I am currently working through trying to come up with a generic method,
    though it is pretty complex to navigate through the objects in a generic
    way. Paticularly since EntitySets are used to refer to collections of
    objects within an object and also to the objects parent object. Which is a
    little odd where the objects have a one-one relationship. For example
    Venue.VenueDetail.Venues is of type EntitySet<Venue>, despite there only
    ever being one Venue. associated to a VenueDetail.

    I am struggling a little with developing the helper method, though it may
    take me a few days work though a solution or decide that I am unable to
    resolve it. Not sure if therefore it is better to add to this issue then
    (further questions or confirmation), or start a new issue if required.

    Please let me know which is best.

    Many Thanks,
    Richard
    RichB, Jun 11, 2009
    #7
  8. Hi Richard,

    >I am struggling a little with developing the helper method, though it may
    >take me a few days work though a solution or decide that I am unable to
    >resolve it. Not sure if therefore it is better to add to this issue then
    >(further questions or confirmation), or start a new issue if required.


    It's difficult to write that method. If it's urgent you can manually assign
    value as mentioned in my previous post to work it around. To get a long
    term solution I recommend you wait for the comment in the connect site. If
    product team improves it in vnext you don't have to do that trouble.

    Regards,
    Allen Chen
    Microsoft Online Support
    Allen Chen [MSFT], Jun 12, 2009
    #8
  9. RichB

    RichB Guest

    Thank Allen ,

    I think I'll probably go along that route, I've played with the reflection
    for a couple of days, and whilst it has been an interesting play, it could
    take me good few days to get it working.

    Thanks for your help.

    Richard


    "Allen Chen [MSFT]" <> wrote in message
    news:eek:s$...
    > Hi Richard,
    >
    >>I am struggling a little with developing the helper method, though it may
    >>take me a few days work though a solution or decide that I am unable to
    >>resolve it. Not sure if therefore it is better to add to this issue then
    >>(further questions or confirmation), or start a new issue if required.

    >
    > It's difficult to write that method. If it's urgent you can manually
    > assign
    > value as mentioned in my previous post to work it around. To get a long
    > term solution I recommend you wait for the comment in the connect site. If
    > product team improves it in vnext you don't have to do that trouble.
    >
    > Regards,
    > Allen Chen
    > Microsoft Online Support
    >
    RichB, Jun 12, 2009
    #9
  10. OK Richard. I'll close this case now. If you have any problems regarding
    reflection please feel free to open a new case in managed newsgroup.

    Thank you for using our Newsgroup Support Service!

    Regards,
    Allen Chen
    Microsoft Online Support
    Allen Chen [MSFT], Jun 15, 2009
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Øyvind Isaksen
    Replies:
    1
    Views:
    946
    Øyvind Isaksen
    May 18, 2007
  2. rmn190
    Replies:
    2
    Views:
    2,333
    Arne Vajhøj
    Jan 10, 2008
  3. shapper
    Replies:
    1
    Views:
    390
    bruce barker
    Sep 28, 2008
  4. Alex. O. Koranteng
    Replies:
    2
    Views:
    574
    Allen Chen [MSFT]
    Jun 10, 2009
  5. RichB
    Replies:
    2
    Views:
    1,210
    RichB
    Jun 4, 2009
Loading...

Share This Page