5

वेब एपीआई और ओडाटा का उपयोग करते हुए डीटीओ का उपयोग करके, मेरे पास एक सेवा है जो इकाई फ्रेमवर्क इकाइयों के बजाय डेटा ट्रांसफर ऑब्जेक्ट्स का खुलासा करती है।ओडीटा और वेब एपीआई

मैं AutoMapper का उपयोग ProjectTo() का उपयोग कर अपने डीटीओ काउंटर भागों में एफई संस्थाओं को बदलने के लिए:

public class SalesOrdersController : ODataController 
{ 
    private DbContext _DbContext; 

    public SalesOrdersController(DbContext context) 
    { 
     _DbContext = context; 
    } 

    [EnableQuery] 
    public IQueryable<SalesOrderDto> Get(ODataQueryOptions<SalesOrderDto> queryOptions) 
    { 
     return _DbContext.SalesOrders.ProjectTo<SalesOrderDto>(AutoMapperConfig.Config); 
    } 

    [EnableQuery] 
    public IQueryable<SalesOrderDto> Get([FromODataUri] string key, ODataQueryOptions<SalesOrderDto> queryOptions) 
    { 
     return _DbContext.SalesOrders.Where(so => so.SalesOrderNumber == key) 
          .ProjectTo<SalesOrderDto>(AutoMapperConfig.Config); 
    } 
} 

AutoMapper (v4.2.1) के रूप में कॉन्फ़िगर किया गया है, ध्यान दें ExplicitExpansion() जो क्रमबद्धता ऑटो नेविगेशन गुण का विस्तार होने से बचाता है, जब वे अनुरोध किया नहीं कर रहे हैं:

cfg.CreateMap<SalesOrderHeader, SalesOrderDto>()     
      .ForMember(dest => dest.SalesOrderLines, opt => opt.ExplicitExpansion()); 

cfg.CreateMap<SalesOrderLine, SalesOrderLineDto>() 
      .ForMember(dest => dest.MasterStockRecord, opt => opt.ExplicitExpansion()) 
      .ForMember(dest => dest.SalesOrderHeader, opt => opt.ExplicitExpansion()); 

ExplicitExpansion() तो एक नई समस्या जहां निम्न अनुरोध एक त्रुटि फेंकता बनाता है:

/odatademo/SalesOrders('123456')?$expand=SalesOrderLines

The query specified in the URI is not valid. The specified type member 'SalesOrderLines' is not supported in LINQ to Entities

नेविगेशन प्रॉपर्टी SalesOrderLines ईएफ के लिए अज्ञात है, इसलिए यह त्रुटि काफी कुछ है जो मुझे होने की उम्मीद है। सवाल यह है कि, मैं इस प्रकार के अनुरोध को कैसे संभाल सकता हूं?

ProjectTo() विधि एक अधिभार मुझे गुण है कि विस्तार की आवश्यकता होती है की एक सरणी में पारित करने के लिए अनुमति देता है कि है, मैंने पाया & संशोधित विस्तार विधि ToNavigationPropertyArray कोशिश करते हैं और एक स्ट्रिंग सरणी में अनुरोध को पार्स करने के लिए:

[EnableQuery] 
public IQueryable<SalesOrderDto> Get([FromODataUri] string key, ODataQueryOptions<SalesOrderDto> queryOptions) 
{ 
    return _DbContext.SalesOrders.Where(so => so.SalesOrderNumber == key) 
      .ProjectTo<SalesOrderDto>(AutoMapperConfig.Config, null, queryOptions.ToNavigationPropertyArray()); 
} 

public static string[] ToNavigationPropertyArray(this ODataQueryOptions source) 
{ 
    if (source == null) { return new string[]{}; } 

    var expandProperties = string.IsNullOrWhiteSpace(source.SelectExpand?.RawExpand) ? new List<string>().ToArray() : source.SelectExpand.RawExpand.Split(','); 

    for (var expandIndex = 0; expandIndex < expandProperties.Length; expandIndex++) 
    { 
     // Need to transform the odata syntax for expanding properties to something EF will understand: 

     // OData may pass something in this form: "SalesOrderLines($expand=MasterStockRecord)";     
     // But EF wants it like this: "SalesOrderLines.MasterStockRecord"; 

     expandProperties[expandIndex] = expandProperties[expandIndex].Replace(" ", ""); 
     expandProperties[expandIndex] = expandProperties[expandIndex].Replace("($expand=", "."); 
     expandProperties[expandIndex] = expandProperties[expandIndex].Replace(")", ""); 
    } 

    var selectProperties = source.SelectExpand == null || string.IsNullOrWhiteSpace(source.SelectExpand.RawSelect) ? new List<string>().ToArray() : source.SelectExpand.RawSelect.Split(','); 

    //Now do the same for Select (incomplete)   
    var propertiesToExpand = expandProperties.Union(selectProperties).ToArray(); 

    return propertiesToExpand; 
} 

इस विस्तार के लिए काम करता है, इसलिए अब मैं निम्नलिखित की तरह एक अनुरोध को पूरा कर सकते हैं:

/odatademo/SalesOrders('123456')?$expand=SalesOrderLines

या की तरह एक और अधिक जटिल अनुरोध:

/odatademo/SalesOrders('123456')?$expand=SalesOrderLines($expand=MasterStockRecord)

हालांकि, और अधिक जटिल अनुरोध है कि $ गठबंधन $ के साथ चयन करने के लिए विस्तार की कोशिश विफल हो जाएगा:

/odatademo/SalesOrders('123456')?$expand=SalesOrderLines($select=OrderQuantity)

Sequence contains no elements

तो, सवाल है: मैं इस सही तरीके से आ रहा हूँ? यह बहुत गंध महसूस करता है कि मुझे समझने के लिए कुछ लिखना होगा और ODataQueryOptions को कुछ ईएफ समझने में बदलना होगा।

ऐसा लगता है यह एक नहीं बल्कि लोकप्रिय विषय है:

हालांकि इनमें से अधिकांश ProjectTo उपयोग करने का सुझाव, कोई भी पता करने के लिए लग रहे हैं serialization ऑटो expan ExplictExpansion को कॉन्फ़िगर किया गया है, या विस्तार को संभालने के लिए कैसे करें।

वर्ग और नीचे कॉन्फ़िग:

इकाई की रूपरेखा (V6.1.3) संस्थाओं:

public class SalesOrderHeader 
{ 
    public string SalesOrderNumber { get; set; } 
    public string Alpha { get; set; } 
    public string Customer { get; set; } 
    public string Status { get; set; } 
    public virtual ICollection<SalesOrderLine> SalesOrderLines { get; set; } 
} 

public class SalesOrderLine 
{ 
    public string SalesOrderNumber { get; set; } 
    public string OrderLineNumber { get; set; }   
    public string Product { get; set; } 
    public string Description { get; set; } 
    public decimal OrderQuantity { get; set; } 

    public virtual SalesOrderHeader SalesOrderHeader { get; set; } 
    public virtual MasterStockRecord MasterStockRecord { get; set; } 
} 

public class MasterStockRecord 
{   
    public string ProductCode { get; set; }  
    public string Description { get; set; } 
    public decimal Quantity { get; set; } 
} 

OData (V6.13।0) डाटा ट्रांसफर वस्तुओं:

public class SalesOrderDto 
{ 
    [Key] 
    public string SalesOrderNumber { get; set; } 
    public string Customer { get; set; } 
    public string Status { get; set; } 
    public virtual ICollection<SalesOrderLineDto> SalesOrderLines { get; set; } 
} 

public class SalesOrderLineDto 
{ 
    [Key] 
    [ForeignKey("SalesOrderHeader")] 
    public string SalesOrderNumber { get; set; } 

    [Key] 
    public string OrderLineNumber { get; set; } 
    public string LineType { get; set; } 
    public string Product { get; set; } 
    public string Description { get; set; } 
    public decimal OrderQuantity { get; set; } 

    public virtual SalesOrderDto SalesOrderHeader { get; set; } 
    public virtual StockDto MasterStockRecord { get; set; } 
} 

public class StockDto 
{ 
    [Key] 
    public string StockCode { get; set; }   
    public string Description { get; set; }   
    public decimal Quantity { get; set; } 
} 

OData कॉन्फ़िग:

var builder = new ODataConventionModelBuilder(); 

builder.EntitySet<StockDto>("Stock"); 
builder.EntitySet<SalesOrderDto>("SalesOrders"); 
builder.EntitySet<SalesOrderLineDto>("SalesOrderLines"); 

उत्तर

0

मैं वास्तव में कभी नहीं इस एक बाहर काम करने में कामयाब रहे। ToNavigationPropertyArray() विस्तार विधि थोड़ा मदद करता है, लेकिन अनंत गहराई नेविगेशन को संभाल नहीं करता है।

असली समाधान क्रियाओं या कार्यों को बनाना है ताकि ग्राहकों को डेटा को अधिक जटिल क्वेरी की आवश्यकता हो।

दूसरा विकल्प क्लाइंट पर डेटा को समेकित करने के लिए कई छोटे/सरल कॉल करना है, लेकिन यह वास्तव में आदर्श नहीं है।

0

जब आप ऑटोमैपर में स्पष्ट विस्तार के लिए कुछ चिह्नित करना चाहते हैं, तो आपको ProjectTo<>() पर कॉल करते समय ऑप्ट-बैक-इन भी करना होगा।

// map 
cfg.CreateMap<SalesOrderHeader, SalesOrderDto>()     
    .ForMember(dest => dest.SalesOrderLines, opt => opt.ExplicitExpansion()); 

// updated controller 
[EnableQuery] 
public IQueryable<SalesOrderDto> Get() 
{ 
    return _dbContext.SalesOrders 
     .ProjectTo<SalesOrderDto>(
      AutoMapperConfig.Config, 
      so => so.SalesOrderLines, 
      // ... additional opt-ins 
     ); 
} 

AutoMapper wiki करता है राज्य इस, उदाहरण शायद एक छोटे से भ्रामक बनती ExplicitExpansion() कॉल शामिल नहीं कर रहा है।

To control which members are expanded during projection, set ExplicitExpansion in the configuration and then pass in the members you want to explicitly expand:

+0

हाय डेव एक सूची प्रदान करेगा। उपर्युक्त कोड उस कोड को दिखाता है जिसका उपयोग मैं इसे कॉन्फ़िगर करने के लिए करता हूं और ओडाटा को पार्स करने के लिए करता हूं ताकि यह पता चल सके कि कौन से नेविगेशन गुणों को विस्तार की आवश्यकता है। यह 'ToNavigationPropertyArray()' एक्सटेंशन विधि का उद्देश्य है, जिसके परिणामस्वरूप 'ProjectTo() 'को पास किया जाता है। मेरा प्रश्न था/ओडाटा क्वेरी स्ट्रिंग को पार्स करने के लिए एक्सटेंशन विधि का उपयोग करना सही दृष्टिकोण था क्योंकि एकाधिक नेविगेशन गुणों को विस्तार करने की आवश्यकता होने पर यह गन्दा हो जाता है। मैंने अधिक जटिल प्रश्नों के लिए कार्यों और कार्यों का उपयोग करके इसके आसपास काम किया। – philreed

0

मैंने एक ऑटोमैपर स्पष्ट नेविगेशन विस्तार उपयोगिता फ़ंक्शन बनाया है जो एन-डेफ विस्तार के साथ काम करना चाहिए। इसे यहां पोस्ट करना क्योंकि यह किसी की मदद कर सकता है।

public List<string> ProcessExpands(IEnumerable<SelectItem> items, string parentNavPath="") 
{ 
    var expandedPropsList = new List<String>(); 
    if (items == null) return expandedPropsList; 

    foreach (var selectItem in items) 
    { 
     if (selectItem is ExpandedNavigationSelectItem) 
     { 
      var expandItem = selectItem as ExpandedNavigationSelectItem; 
      var navProperty = expandItem.PathToNavigationProperty?.FirstSegment?.Identifier; 

      expandedPropsList.Add($"{parentNavPath}{navProperty}");      
      //go recursively to subproperties 
      var subExpandList = ProcessExpands(expandItem?.SelectAndExpand?.SelectedItems, $"{navProperty}."); 
      expandedPropsList = expandedPropsList.Concat(subExpandList).ToList(); 
     } 
    } 
    return expandedPropsList; 
} 

आप से कॉल करने की कर सकते हैं:

var navExp = ProcessExpands(options?.SelectExpand?.SelectExpandClause?.SelectedItems) 

यह, मैं पहले से ही स्पष्ट रूप से नेविगेशन गुण का विस्तार कर रहा हूँ के साथ ["Parent" ,"Parent.Child"]

संबंधित मुद्दे