使用odata更新任何属性

时间:2013-01-15 16:02:46

标签: c# .net entity-framework wcf-data-services odata

您知道如何使用OData语法更新WCF数据服务中的实体而不使用实体的密钥属性。

例如,实体:

public class Product
{
    [Key]
    public int Id { get; set; }

    public string Reference { get; set; }
}

我想提出这个要求:

PUT myservice.svc/Product('REFXX') 
与'REFXXX'对应的

执行Reference属性(这是唯一的)。

有什么想法吗?

2 个答案:

答案 0 :(得分:0)

目前无法做到这一点 - 问题是如果您将以下请求传递给服务器(PUT myservice.svc / Product('REFXX')),服务器将如何知道REFXX是该值的值独特的财产,而不是关键财产。

如果您确实想要根据唯一属性更新客户端,请确保服务器将该唯一属性公开为密钥。

由于 PRATIK

答案 1 :(得分:0)

我编写了一个IDispatchMessageInspector,解析了url,并使用正确的语法和真实密钥替换了request参数中的match元素。我知道密钥不是具有特定用户代理的真正“密钥”,或者是Service.svc / Entity(SecondaryKey = value)的语法,它通常用于多个pk。

所以在AfterReceiveRequest方法中,进程是:

  • 解析网址Service.svc / Entity(SecondaryKey = value)
  • 获取实体的键值(通过构建动态linq表达式)
  • 使用Service.svc / Entity(PKValue)更改请求的匹配元素

           public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel, System.ServiceModel.InstanceContext instanceContext)
    {
    
        if (request.Properties.ContainsKey("UriTemplateMatchResults") && HttpContext.Current != null)
        {
            //get match for current request
            UriTemplateMatch match = (UriTemplateMatch)request.Properties["UriTemplateMatchResults"];
    
            Utils.ODataBasicUriParser uriParser = new Utils.ODataBasicUriParser(match.RequestUri.PathAndQuery);
    
            //verify if this is a SecondaryKey request
            if (uriParser.IsEntityQuery && uriParser.IsSecondaryKeyQuery)
            {               
                //TODO this syntax is also used for entities with multiple pk's, test it
    
                //get a new data context
                //TODO see if this can be improved, avoid two datacontext for one request 
                DataContext ctx = new DataContext();
    
                Type outType;
                //get entity type name from the service name 
                string entityName = DataContext.GetEntityNameByServiceName(uriParser.EntityServiceName);
    
                //get the pk for the entity
                string id = ctx.GetEntityId(entityName, uriParser.EntityKey, uriParser.EntityId, out outType);
    
                //verify if the pk has been found or cancel this to continue with standart request process
                if (string.IsNullOrEmpty(id))
                {
                    Trace.TraceWarning(string.Format("Key property not found for the the entity:{0}, with secondaryKeyName:{1} and secondaryKeyValue:{2}",
                        entityName, uriParser.EntityKey, uriParser.EntityId));
    
                    return System.Net.HttpStatusCode.NotFound;
                }
    
                //in odata syntax quotes are required for string values, nothing for numbers
                string quote = outType.FullName == typeof(Int32).FullName || outType.FullName == typeof(Int64).FullName ? string.Empty : "'";
    
                //build the new standart resource uri with the primary key
                var newUri = new Uri(string.Format("{0}/{1}({2}{3}{2})", match.BaseUri.ToString(), uriParser.EntityServiceName, quote, id));
    
                //create a new match to replace in the current request, with the new Uri
                UriTemplateMatch newMatch = NewMatch(match, newUri); 
    
                //set request values
                request.Properties["UriTemplateMatchResults"] = newMatch;
                request.Headers.To = newUri;
                request.Properties.Via = newUri;
            }
        }
    
        return null;
    }
    
    
    UriTemplateMatch NewMatch(UriTemplateMatch match, Uri newUri)
    {
        UriTemplateMatch newMatch = new UriTemplateMatch();
        newMatch.RequestUri = newUri;
        newMatch.Data = match.Data;
        newMatch.BaseUri = match.BaseUri;
    
        return newMatch;
    }
    

适合我目前的需求