odata v4 client code generator: how to do deep ins

2019-09-16 02:33发布

问题:

What I have is something like

var item1 = new Item { CODE = "ABC1", NAME = "A B C 1" };
var item2 = new Item { CODE = "ABC2", NAME = "A B C 2" };
var items = new DataServiceCollection<Item >{ item1, item2 };
var mt    = new MyType { CURRDATE = DateTime.Now.toString(), ITEMS = items };
_container.AddToMyType(mt);
var resp = _container.SaveChanges();
//...etc

is that right? it's complaining something about

"Unhandled Exception: System.InvalidOperationException: An item could not be added to the collection. When items in a DataServiceCollection are tracked by the DataServiceContext, new items cannot be added before items have been loaded into the collection."

回答1:

As far as I know, OData v4 client does not support deep insert.

One way to do this is to create an OData Action method and serialize the entity before sending to the OData Action method and send as a string, then deserialize it on the server side.

Another option I have listed below will let you do "POST" with parent / child:

/// <summary>
/// Deep insert parent and child.
/// </summary>
/// <param name="parentEntityPluralName"></param>
/// <param name="entity"></param>
public TEntity SaveWithChildren<TEntity>(string parentEntityPluralName, TEntity entity) where TEntity : BaseEntityType
{
    // need to serialize the entity so that we can send parent and child together
    string serializedEntity = Newtonsoft.Json.JsonConvert.SerializeObject(entity, new Newtonsoft.Json.JsonSerializerSettings() { ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore });

    // create a handler for the httpclient
    using (System.Net.Http.HttpClientHandler httpHandler = new System.Net.Http.HttpClientHandler())
    {
        // create the httpclient and add the handler
        using (System.Net.Http.HttpClient httpClient = new System.Net.Http.HttpClient(httpHandler))
        {
            // setup the headers
            httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Prefer", @"odata.include-annotations=""*""");
            httpClient.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "application/json;odata.metadata=minimal");

            // setup the content to send
            using (System.Net.Http.StringContent odataContent = new System.Net.Http.StringContent(serializedEntity))
            {
                // setup the content type to json
                odataContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");

                // post the data to the odata service
                using (System.Net.Http.HttpResponseMessage response = httpClient.PostAsync(this.BaseUri + parentEntityPluralName, odataContent).Result)
                {
                    // get back any errors or content
                    string content = response.Content.ReadAsStringAsync().Result;

                    // show error if service failed
                    if (response.IsSuccessStatusCode == false)
                    {
                        throw new Exception(content);
                    }

                    // try to convert the object back from the service call
                    return Newtonsoft.Json.JsonConvert.DeserializeObject<TEntity>(content);
                }
            }
        }
    }
}

Place this method in a new class that is partial to your "proxy" generated class.
Then call your Container class and call the SaveWithChildren method.
This will call you parent controllers POST method.
It ONLY calls the parent controller POST method and you will have to iterate the children on the server.



标签: c# .net odata