locked
How to add a new many-to-many relationship? RRS feed

  • Question

  •  

    My entity model has a many-to-many relationship between Project entities and User entities via a ProjectOwnership entity. What steps must I go through to add a new User to a Project via the client library?

     

    I've tried many different combinations of code, the latest of which is this:

     

    Code Snippet

    // Create intermediate entity using generated proxy class method

    ProjectOwnership ownership = ProjectOwnership.CreateProjectOwnership(user.USER_ID, project.PROJECT_ID);

    _context.AddObject("PROJECT_OWNERSHIP", ownership);

     

    // Add references to target objects

    ownership.PROJECT = project;

    ownership.USER = user;

    _context.UpdateObject(ownership);

     

    // Add references to ownership objects

    project.PROJECT_OWNERSHIP.Add(ownership);

    _context.UpdateObject(project);

    user.PROJECT_OWNERSHIP.Add(ownership);

    _context.UpdateObject(user);

     

    // Commit the changes

    _context.BeginSaveChanges(SaveChangesOptions.Batch, new AsyncCallback(OnSaveComplete), null);

     

     

    where user and project are pre-existing entities within the context.

     

    When I iterate throught the OperationResponse objects in the DataServiceResponse returned in the async callback I see that a BadRequest error has occured with the following stack trace:

     

       at System.Data.Services.Client.DataServiceContext.HandleResponse(HttpStatusCode statusCode, Func`1 getResponseStream, Boolean throwOnFailure)
       at System.Data.Services.Client.DataServiceContext.SaveAsyncResult.d__4.MoveNext()

     

    I have no idea what that means or how to debug it. I have run SQL profiler and no query has been executed so I don't believe the problem is with the generated query. Can anyone tell me what I am doing wrong here or suggest an approach toward getting to the bottom of this?

     

    Thanks

    Rob

     

     

    Monday, June 23, 2008 10:27 PM

Answers

All replies

  • Any takers?

     

    When I analyze the HTTP activity in the scenario above with Fiddler, I see that the problem seems to be with adding the intermediate entity. The Bad Request error occurs in response to the following request:

     

    Code Snippet

    POST /MyDataService.svc/PROJECT_OWNERSHIP HTTP/1.1

    If-Modified-Since: 11/15/1995 12:00:00 AM

    Accept-Language: en-us

    Referer: http://127.0.0.1.:3345/SilverlightProjectDemoTestPage.aspx

    Accept: application/atom+xml,application/xml

    Accept-Charset: UTF-8

    Content-Type: application/atom+xml

    UA-CPU: x86

    Accept-Encoding: gzip, deflate

    User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022; .NET CLR 3.5.30428)

    Host: 127.0.0.1.:3345

    Content-Length: 773

    Connection: Keep-Alive

    Pragma: no-cache

    Cookie: .ASPXAUTH=83B7B8BFBB73407CB441D94FC96380A65392349D7446C8BC2073EA013F5B2853D910C6FE0F502D071BA2C4934A2A197D65B53B3A1CF256678765FE475C8F2D78DFDB4FE1B6133D85CF28405A2A134747

    <?xml version="1.0" encoding="utf-8" standalone="yes"?>

    <entry xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata" xmlns="http://www.w3.org/2005/Atom">

    <content type="application/xml">

    <m:properties>

    <d:PROJECT_ID>e66661c5-f5be-4336-93dc-ddaa3f8631ea</d:PROJECT_ID>

    <d:USER_ID>8c85fcca-cdf8-4306-bd43-9efdcd758588</d:USER_ID>

    <d:CREATED_BY_ID m:null="true" />

    <d:DATE_CREATED m:null="true" />

    <d:DATE_UPDATED m:null="true" />

    <d:DELETED>0</d:DELETED>

    <d:EXTERNAL_KEY m:null="true" />

    <d:EXTERNAL_VALUE m:null="true" />

    <d:UPDATED_BY_ID m:null="true" />

    </m:properties>

    </content>

    </entry>

     

     

     

    What is wrong with this request?
    Tuesday, June 24, 2008 7:02 PM
  • There is another important piece of information that I neglected to include in my original problem description in an effort to simplify the problem description. Now I am realizing that this missing piece of data may be the root of the entire problem.

     

    The ProjectOwnership entity created in the code above inherits from the PROJECT_OWNERSHIP entity. The inheritance is based on the value of a non-null column in the underlying PROJECT_OWNERSHIP DB table but that field is not visible as a property of the ProjectOwnership proxy class (I guess that would defeat the purpose of inheritance). When my code creates a new ProjectOwner entity and calls SaveChanges, the Fiddler trace does not show a value for that field being sent in the POST. Since I can't indicate the inherited type in the POST and I can't set the value of the inheritance condition, there is really no way for the entity model to know what kind of object I am creating.

     

    Am I correct in my belief that inheritance is the cause of my problem? Does Astoria even support this inheritance scenario? If not, is there any way to work around the problem short of eliminating inheritance from my entity model?

     

    Thanks

    Rob

     

    Tuesday, June 24, 2008 7:52 PM
  • This problem was solved when I implemented ResolveNames as suggested in

     

    http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=3535951&SiteID=1

     

     

    Thursday, June 26, 2008 4:46 PM
  • Hi Rob,

    Am facing the same problem. Can you show the code how you used it?

    Thanks,
    Peter

     

    Thursday, June 26, 2008 4:54 PM
  • Also, how did you get the intermediate table to show as an object?  In my model, there is no reference to the intermediate table class used in the many--to-many. Do you have fields other than the keys (which would necessarily make the table show up).
    Thursday, June 26, 2008 5:01 PM
  • Peter,

     

    First I had to set up a name resolver. I had to do this because in my case ProjectOwner inherits from PROJECT_OWNERSHIP based on a field in the PROJECT_OWNERSHIP table of my DB.

    Code Snippet

    TheContext.ResolveName = new Func<Type, string>(ResolveMyName);

     

    public string ResolveMyName(Type type)

    {

    return type.FullName;

    }

     

     

     

    To add the relationship between a Project and a User, I used the following code;

     

    Code Snippet

    ProjectOwner ownership = ProjectOwner.CreateProjectOwner(user.USER_ID, project.PROJECT_ID, 0);

    TheContext.AddObject("PROJECT_OWNERSHIP", ownership);

    TheContext.AddLink(ownership, "PROJECT", project);

    TheContext.AddLink(ownership, "USER", user);

    TheContext.UpdateObject(ownership);

    project.PROJECT_OWNERSHIP.Add(ownership);

    TheContext.UpdateObject(project);

    user.PROJECT_OWNERSHIP.Add(ownership);

    TheContext.UpdateObject(user);

    TheContext.BeginSaveChanges(SaveChangesOptions.Batch, new AsyncCallback(OnSaveComplete), null);

     

     

    Hope that helps.

     

    Rob

    Thursday, June 26, 2008 5:12 PM
  • Thanks much.
    Thursday, June 26, 2008 5:33 PM