2009-06-16 15 views
12

Thu hút phản hồi/tùy chọn/nhận xét về mẫu "tốt nhất" để sử dụng cho dữ liệu tham chiếu trong các dịch vụ của tôi.Hợp đồng Dữ liệu WCF và Dữ liệu Thực thể Tham chiếu?

Tôi có ý gì với dữ liệu tham chiếu?

Hãy sử dụng Northwind làm ví dụ. Đơn đặt hàng có liên quan đến Khách hàng trong cơ sở dữ liệu. Khi tôi triển khai Dịch vụ đặt hàng của mình, trong một số trường hợp, tôi muốn tham chiếu một Khách hàng "đầy đủ" từ một Đơn hàng và các trường hợp khác khi tôi chỉ muốn tham chiếu đến Khách hàng (ví dụ: cặp Khóa/Giá trị). Ví dụ, nếu tôi đang làm một GetAllOrders(), tôi sẽ không muốn trả lại một Lệnh được điền đầy đủ, tôi muốn trả lại một phiên bản nhẹ của một Đơn đặt hàng chỉ với dữ liệu tham chiếu cho mỗi Khách hàng của đơn đặt hàng. Tuy nhiên, nếu tôi đã làm một phương thức GetOrder(), tôi có thể muốn điền vào các chi tiết của Khách hàng bởi vì rất có thể là một người tiêu dùng của phương thức này có thể cần nó. Có thể có các tình huống khác mà tôi có thể muốn hỏi rằng các chi tiết của Khách hàng được điền vào trong một số cuộc gọi phương thức nhất định, nhưng bị bỏ qua cho những người khác.

Dưới đây là những gì tôi đã đi lên với:

[DataContract] 
public OrderDTO 
{ 
    [DataMember(Required)] 
    public CustomerDTO; 

    //etc.. 
} 

[DataContract] 
public CustomerDTO 
{ 
    [DataMember(Required)] 
    public ReferenceInfo ReferenceInfo; 

    [DataMember(Optional)] 
    public CustomerInfo CustomerInfo; 
} 

[DataContract] 
public ReferenceInfo 
{ 
    [DataMember(Required)] 
    public string Key; 

    [DataMember(Required)] 
    public string Value; 
} 

[DataContract] 
public CustomerInfo 
{ 
    [DataMember(Required)] 
    public string CustomerID; 

    [DataMember(Required)] 
    public string Name; 

    //etc.... 
} 

Những suy nghĩ ở đây là kể từ ReferenceInfo (mà là một cặp khóa/giá trị gia tăng chung) luôn luôn cần thiết trong CustomerDTO, tôi luôn luôn sẽ có ReferenceInfo . Nó cung cấp cho tôi đủ thông tin để có được chi tiết Khách hàng sau này nếu cần. Nhược điểm để có CustomerDTO yêu cầu ReferenceInfo là nó có thể quá mức cần thiết khi tôi nhận được đầy đủ CustomerDTO (tức là với CustomerInfo điền vào), nhưng ít nhất tôi được đảm bảo thông tin tham khảo.

Có một số mẫu hoặc khung công tác khác mà tôi có thể sử dụng để làm cho kịch bản/triển khai này "sạch hơn" không?

Lý do tôi hỏi là mặc dù chúng tôi có thể chỉ đơn giản nói trong Northwind để LUÔN LUÔN trả lại một CustomerDTO đầy đủ, điều đó có thể hoạt động tốt trong tình huống Northwind đơn giản. Trong trường hợp của tôi, tôi có một đối tượng có 25-50 trường dữ liệu tham chiếu/tra cứu. Một số là quan trọng hơn để tải hơn những người khác trong các tình huống khác nhau, nhưng tôi muốn có càng ít định nghĩa của các loại tài liệu tham khảo càng tốt (để tôi không nhận được vào "địa ngục bảo trì DTO").

Ý kiến? Phản hồi? Bình luận?

Cảm ơn!

+0

FWIW ... Tôi không nghĩ LINQ to SQL, Entity Framework hoặc ADO.Dịch vụ dữ liệu NET sẽ giúp tôi ở đây, vì tôi có 3 hệ thống khác nhau, tất cả đại diện, về cơ bản, cùng một tập dữ liệu. Đây là bước đầu tiên để củng cố các hệ thống này, hoặc ít nhất là cho các hệ thống bên ngoài để có thể tiêu thụ dữ liệu từ ba hệ thống này một cách chung chung và nhất quán hơn. – Brian

+0

Bạn có thể trả lời http://stackoverflow.com/questions/9483286/understanding-data-outside-of-service-soa không? – Lijo

Trả lời

1

Dường như là một giải pháp phức tạp đối với tôi. Tại sao không chỉ có một trường id khách hàng trong lớp OrderDTO và sau đó cho phép ứng dụng quyết định trong thời gian chạy cho dù nó có cần dữ liệu khách hàng hay không. Vì nó có id khách hàng nên nó có thể kéo dữ liệu xuống khi nó quyết định.

+0

Tôi sẽ phơi bày khả năng nhận dữ liệu Khách hàng được cấp cho CustomerID, nhưng cố gắng tránh giao diện "trò chuyện". – Brian

+0

Xây dựng dựa trên ý nghĩa của giao diện "trò chuyện". Giả sử tôi hiển thị kết quả của GetAllOrders() trong một lưới. Một cột trong lưới là "Tên khách hàng". Tôi sẽ không muốn gọi cho GetCustomer() cho mọi đơn đặt hàng tôi hiển thị trong lưới. Ngoài ra, tôi không muốn hủy hợp đồng của mình nếu yêu cầu mới nêu rằng ngoài Tên khách hàng, chúng tôi cũng cần hiển thị, ví dụ: Số điện thoại của khách hàng. Tôi chỉ muốn có thể chuyển lời gọi phương thức của mình sang một cái gì đó như vậy:
GetAllOrders (expandReference = true); Lưu ý: không chắc liệu Điện thoại có thực sự ở Northwind hay không. – Brian

+0

Vì vậy, bạn sẽ có logic trả về một phần chi tiết khách hàng dựa trên các cặp khóa-giá trị trong CustomerDTO? Phải mất một thời gian để nắm bắt cơ chế của bạn mà có thể là một dấu hiệu quá phức tạp hoặc tôi chậm. Nếu đó là tôi, tôi chắc chắn sẽ cố gắng làm điều đó chỉ với hai lớp: Đặt hàng và Khách hàng. Thêm một phương thức bổ sung vào giao diện của bạn để nói GetAllOrdersPartial() có vẻ kém hơn rất nhiều so với việc tạo ra các lớp bổ sung hơi mơ hồ. Nếu tôi đã có để duy trì mã của bạn tôi muốn một vài cuộc gọi phương pháp bổ sung thay vì làm việc ra một số tối ưu hóa khôn lanh cho cùng một hiệu ứng. – sipwiz

1

Tôi đã quyết định chống lại cách tiếp cận mà tôi sắp thực hiện. Tôi nghĩ rằng nhiều mối quan tâm ban đầu của tôi là kết quả của việc thiếu các yêu cầu. Tôi đã kỳ vọng đây là trường hợp, nhưng tò mò muốn xem những người khác có thể giải quyết vấn đề này như thế nào khi xác định thời điểm tải lên một số dữ liệu nhất định và khi nào thì không.

Tôi đang làm phẳng Hợp đồng dữ liệu để chứa các trường dữ liệu tham chiếu được sử dụng nhiều nhất. Điều này sẽ làm việc cho phần lớn người tiêu dùng. Nếu dữ liệu được cung cấp không đủ cho một người tiêu dùng cụ thể, họ sẽ có tùy chọn để truy vấn một dịch vụ riêng biệt để lấy lại chi tiết đầy đủ cho một thực thể tham chiếu cụ thể (ví dụ: Tiền tệ, Nhà nước, v.v.). Đối với các tra cứu đơn giản thực sự là các cặp khóa/giá trị cơ bản, chúng ta sẽ xử lý chúng với một cặp hợp lệ dữ liệu cặp khóa/giá trị chung. Tôi thậm chí có thể sử dụng thuộc tính KnownType cho các cặp khóa/giá trị chuyên biệt hơn.

[DataContract] 
public OrderDTO 
{ 
    [DataMember(Required)] 
    public CustomerDTO Customer; 

    //in this case, I think consumers will need currency data, 
    //so I pass back a full currency item 
    [DataMember(Required)] 
    public Currency Currency; 

    //in this case, I think consumers are not likely to need full StateRegion data, 
    //so I pass back a "reference" to it 
    //User's can call a separate service method to get full details if needed, or 
    [DataMember(Required)] 
    public KeyValuePair ShipToStateRegion; 

    //etc.. 
} 


[DataContract] 
[KnownType(Currency)] 
public KeyValuePair 
{ 
    [DataMember(Required)] 
    public string Key; 

    [DataMember(Required)] 
    public string Value; 

    //enum consisting of all possible reference types, 
    //such as "Currency", "StateRegion", "Country", etc. 
    [DataMember(Required)] 
    public ReferenceType ReferenceType; 
} 


[DataContract] 
public Currency : KeyValuePair 
{ 
    [DataMember(Required)] 
    public decimal ExchangeRate; 

    [DataMember(Required)] 
    public DateTime ExchangeRateAsOfDate; 
} 


[DataContract] 
public CustomerDTO 
{ 
    [DataMember(Required)] 
    public string CustomerID; 

    [DataMember(Required)] 
    public string Name; 

    //etc.... 
} 

Suy nghĩ? Ý kiến? Bình luận?

+0

Điều này nghe có vẻ giống như một thỏa hiệp hợp lý, nhưng được chuẩn bị cho một chút điều chỉnh và tinh chỉnh cho đến khi bạn tìm ra những "tập hợp con chung" của thuộc tính nên được. Và nếu dự án này chủ yếu cho mục đích báo cáo hoặc phân tích, luôn có khả năng là sẽ không có một tập hợp con chung nào cả. Và điều đó dẫn bạn quay lại ngay để cần nhiều lần lặp lại. – dthrasher

+0

@ Brian- Mặc dù đây là một câu hỏi cũ tôi đã thêm một câu trả lời liên quan đến cách Amazon làm điều đó, vì bạn có thể thấy nó hữu ích. – RichardOD

2

Chúng tôi đang ở cùng một điểm quyết định trong dự án của mình. Ngay bây giờ, chúng tôi đã quyết định tạo ba cấp DTO để xử lý Thing: SimpleThing, ComplexThing và FullThing. Tuy nhiên, chúng tôi không biết làm thế nào nó sẽ làm việc cho chúng tôi, vì vậy đây chưa phải là một câu trả lời căn cứ vào thực tế.

Một điều tôi tự hỏi là nếu chúng ta có thể biết rằng các dịch vụ của chúng tôi được thiết kế ở mức "sai". Ví dụ, có bao giờ một trường hợp mà chúng ta nên phá vỡ một FullThing ngoài và chỉ vượt qua một SimpleThing? Nếu chúng ta làm, điều đó có nghĩa là chúng ta đã đặt một số logic kinh doanh ở mức quá cao?

+0

Nó có hiệu quả với bạn không? Tôi nghiêng về hướng tiếp cận này. – Jonn

1

Chúng tôi cũng đã đối mặt với vấn đề này trong ánh xạ đối tượng-quan hệ. Có những tình huống mà chúng tôi muốn đối tượng đầy đủ và những người khác mà chúng tôi muốn tham chiếu đến nó.

Khó khăn là bằng cách nướng tuần tự hóa vào các lớp, mẫu dữ liệu datacontract thực thi ý tưởng chỉ có một cách đúng để sắp xếp một đối tượng. Nhưng có rất nhiều kịch bản mà bạn có thể muốn sắp xếp từng phần một lớp và/hoặc các đối tượng con của nó.

Điều này thường có nghĩa là bạn phải có nhiều DTO cho mỗi lớp. Ví dụ: một FullCustomerDTO và CustomerReferenceDTO. Sau đó, bạn phải tạo các cách để ánh xạ các DTO khác nhau trở lại đối tượng miền của Khách hàng.

Như bạn có thể tưởng tượng, đó là một tấn công việc, phần lớn nó rất tẻ nhạt.

+0

Bạn có thể vui lòng trả lời http://stackoverflow.com/questions/9483286/understanding-data-outside-of-service-soa? – Lijo

1

Một khả năng khác là xử lý các đối tượng như túi tài sản. Chỉ định các thuộc tính bạn muốn khi truy vấn và lấy lại chính xác các thuộc tính bạn cần.

Thay đổi thuộc tính để hiển thị trong phiên bản "ngắn" sau đó sẽ không yêu cầu nhiều chuyến đi vòng, bạn có thể nhận tất cả thuộc tính cho một tập hợp cùng một lúc (tránh giao diện trò chuyện) và bạn không phải sửa đổi dữ liệu hoặc hợp đồng hoạt động của bạn nếu bạn quyết định bạn cần các thuộc tính khác nhau cho phiên bản "ngắn".

+0

Việc xử lý các thuộc tính như chính các đối tượng là một ý tưởng tôi đã đẩy. Tôi nghĩ rằng điều này sẽ cho phép tính linh hoạt để kéo bất kỳ thuộc tính nào tôi muốn. Điều này cho biết, nó giới thiệu một mức độ phức tạp trên hệ thống khi chúng ta không còn đối phó với các đối tượng có các trường kiểu gốc trên chúng, mà là một tập hợp các "đối tượng trường". Sự trừu tượng mang lại cho bạn sự linh hoạt, nhưng với chi phí phức tạp (và có thể bảo trì). Tôi tìm thấy trong tình huống cụ thể của tôi, phần lớn các nhà phát triển khác thấy giải pháp này quá phức tạp để nắm bắt. – Brian

+1

Cả hai không nhất thiết phải độc quyền. API công khai của bạn có thể có các trường được nhập tĩnh, trong khi sử dụng một túi thuộc tính làm việc triển khai cơ bản. Bạn cũng có thể phơi bày (trực tiếp hoặc gián tiếp) túi để cho phép bổ sung năng động của "trường" trong khi vẫn duy trì các thuộc tính tĩnh cho các công cụ tĩnh đã biết. – kyoryu

+0

Để cụ thể hơn, không có lý do gì mà hợp đồng WCF phải khớp với API được sử dụng bởi người tiêu dùng của đối tượng, và trên thực tế, tôi thường khuyên bạn nên tốt hơn trong thời gian dài nếu bạn làm rõ lên phía trước. – kyoryu

2

Dịch vụ web API quảng cáo sản phẩm Amazon là một ví dụ hay về cùng một vấn đề mà bạn đang gặp phải.

Họ sử dụng các DTO khác nhau để cung cấp cho người gọi nhiều chi tiết hơn tùy thuộc vào hoàn cảnh của họ. Ví dụ: có small response group, large response group và ở giữa medium response group.

Có các DTO khác nhau là một kỹ thuật tốt nếu như bạn nói bạn không muốn có giao diện trò chuyện.

+0

Chỉ cần tự hỏi, làm cách nào bạn sắp xếp nhóm phản hồi Nhỏ, Trung bình, Lớn trong một hệ thống phân cấp thừa kế? Liệu các ORM luôn luôn tồn tại một DTO lớn và sau đó có các DTO nhỏ và DTO trung bình chỉ làm trình bao bọc? – Jonn

+0

@RichardOD Bạn có thể trả lời http://stackoverflow.com/questions/9483286/understanding-data-outside-of-service-soa không? – Lijo

1

Tôi thường xây dựng tải chậm vào các dịch vụ web phức tạp của mình (ví dụ: dịch vụ web gửi/nhận đối tượng). Nếu một người có tài sản Cha (cũng là một người), tôi chỉ gửi một định danh cho Cha thay vì đối tượng lồng nhau, thì tôi đảm bảo rằng dịch vụ web của tôi có một hoạt động có thể chấp nhận mã nhận diện và trả lời với thực thể Person tương ứng . Sau đó, khách hàng có thể gọi lại dịch vụ web nếu muốn sử dụng thuộc tính Cha.

Tôi cũng đã mở rộng để điều này có thể xảy ra. Nếu một hoạt động gửi lại 5 Người, thì nếu tài sản của Cha được truy cập trên bất kỳ một trong những Người đó, thì một yêu cầu được đưa ra cho tất cả 5 Người cha với số nhận dạng của họ. Điều này giúp giảm sự chattiness của dịch vụ web.

+0

Lưu ý sử dụng chiến lược này yêu cầu nhận thức cấp tính về nhận dạng đối tượng.Bạn có thể không muốn nhiều phiên bản của cùng một Thực thể nổi xung quanh; vì vậy bạn có thể muốn tạo bộ nhớ cache trên máy khách của các thực thể bạn đã nhận được cho đến nay và sử dụng bộ nhớ cache bạn đã cung cấp để quay lại để có một bản sao khác. –