2009-03-24 68 views
59

Tôi đã nhìn thấy rất nhiều câu hỏi liên quan đến ánh xạ DTO cho đối tượng miền, nhưng tôi không cảm thấy họ đã trả lời câu hỏi của tôi. Tôi đã sử dụng nhiều phương pháp trước và có ý kiến ​​riêng của mình nhưng tôi đang tìm kiếm thứ gì đó cụ thể hơn một chút.Thực tiễn tốt nhất để ánh xạ DTO cho đối tượng miền?

Tình hình:

Chúng tôi có nhiều đối tượng miền. Chúng tôi đang sử dụng mô hình CSLA để các đối tượng miền của chúng tôi có thể khá phức tạp và chúng chứa quyền truy cập dữ liệu của riêng họ. Bạn không muốn vượt qua những xung quanh trên dây. Chúng tôi sẽ viết một số dịch vụ mới sẽ trả về dữ liệu ở một số định dạng (.Net, JSON, v.v.). Vì lý do này (và các lý do khác), chúng tôi cũng đang tạo một đối tượng truyền dữ liệu, nạc để truyền xung quanh trên dây.

Câu hỏi của tôi là đối tượng DTO và miền được kết nối như thế nào?

Phản ứng đầu tiên của tôi là sử dụng Fowler, DTO pattern-type solution. Tôi đã nhìn thấy điều này được thực hiện nhiều lần và nó cảm thấy phù hợp với tôi. Đối tượng miền không chứa tham chiếu đến DTO. Một thực thể bên ngoài (một "mapper" hoặc "assembler") được gọi để tạo DTO từ một đối tượng miền. Thông thường có một ORM ở phía đối tượng miền. Nhược điểm của điều này là "người lập bản đồ" có xu hướng cực kỳ phức tạp cho bất kỳ tình huống thực tế nào và có thể rất mong manh.

Một ý tưởng khác được đưa ra là để đối tượng miền "chứa" DTO, vì nó chỉ là một đối tượng dữ liệu gọn gàng. Các thuộc tính đối tượng miền sẽ tham chiếu nội bộ các thuộc tính DTO và chỉ có thể trả về DTO nếu được yêu cầu. Tôi có thể thấy không có vấn đề với điều này nhưng nó cảm thấy sai. Tôi đã thấy một số bài viết mà mọi người sử dụng NHibernate xuất hiện để sử dụng phương pháp này.

Có cách nào khác không? Là một trong những cách trên giá trị sử dụng? Nếu có hay không, tại sao?

Cảm ơn mọi thông tin chi tiết trước.

+2

Trình tự động trông thú vị. Tôi đã nhìn thấy rất nhiều mã trước khi nó sẽ thay thế. Vấn đề chính của tôi là nếu tôi bị mắc kẹt với một tấn mã lập bản đồ vì lý do gì đó, tôi muốn tự mình kiểm soát nó hơn. –

+2

Khi chúng tôi đi từ DTOs _to_ Domain Objects, ánh xạ đó là 100% thủ công. Đó là một vấn đề khó giải quyết hơn, vì chúng tôi cố gắng giữ cho các đối tượng miền hoạt động dựa trên cơ sở, thay vì chỉ đơn thuần là các thùng chứa dữ liệu. Đi _to_ một DTO, đó là một vấn đề dễ giải quyết. –

+0

Tôi sẽ đồng ý rằng nó là sai trong đó đối tượng miền nên không có kiến ​​thức về đối tượng dto. Trong khi chúng có thể liên quan trong trường hợp này, mục đích của chúng hoàn toàn tách biệt (các dtos thường được tạo ra cho mục đích) và bạn sẽ tạo ra một sự phụ thuộc không cần thiết. – Sinaesthetic

Trả lời

33

Lợi ích của việc có người lập bản đồ nằm giữa tên miền của bạn và DTO của bạn không xuất hiện khi bạn chỉ hỗ trợ ánh xạ đơn, nhưng khi số lượng ánh xạ tăng lên, mã đó được phân tách khỏi miền sẽ giúp giữ miền đơn giản và gọn gàng hơn. Bạn sẽ không làm lộn xộn miền của bạn với rất nhiều trọng lượng.

Cá nhân, tôi cố gắng và giữ bản đồ ra khỏi các thực thể miền của mình và đặt trách nhiệm vào cái mà tôi gọi là "Lớp người quản lý/dịch vụ". Đây là một lớp nằm giữa ứng dụng và (các) bộ nhớ, và cung cấp logic nghiệp vụ như phối hợp công việc (Nếu bạn sửa đổi A, bạn có thể cũng phải sửa đổi B để dịch vụ A sẽ làm việc với Dịch vụ B).

Nếu có nhiều định dạng kết thúc, tôi có thể xem xét việc tạo trình định dạng có thể cắm được có thể sử dụng mẫu Khách truy cập, ví dụ để chuyển đổi thực thể của tôi, nhưng tôi chưa tìm thấy nhu cầu.

22

Bạn có thể sử dụng công cụ tự động hóa như the one written by Jimmy Bogard không có kết nối giữa các đối tượng và dựa vào các quy ước đặt tên được tuân thủ.

+3

Máy tự động có thể dẫn đến các đặc tính bị phơi nhiễm vô tình -> lỗ hổng bảo mật. Nó sẽ là tốt hơn để nói một cách rõ ràng những gì cần được tiếp xúc như là một DTO. – deamon

+4

@deamon: mối quan tâm hợp lệ, nhưng do đó là các lỗi (và lỗ hổng bảo mật tiềm năng do giám sát của con người) có thể được tạo ra bằng cách viết tất cả mã lập bản đồ gooey đó. Tôi sẽ đi đường automagic và xử lý 5% bằng cách sử dụng nó được xây dựng trong tính năng lập bản đồ tùy chỉnh. – Merritt

+0

@deamon - bạn không thể chỉ lập bản đồ có điều kiện cho những thuộc tính mà bạn không nên để lộ? Suy nghĩ AutoMapper xử lý kịch bản đó? –

1

Một giải pháp khả thi: http://glue.codeplex.com.

Các tính năng:

  • hai chiều mapping
  • lập bản đồ tự động
  • Mapping giữa các loại khác nhau
  • lập bản đồ lồng nhau và cầu dẹt
  • Lists và Mảng
  • Việc xác minh các mối quan hệ
  • Kiểm tra các ánh xạ
  • Thuộc tính, trường và phương pháp
5

Chúng tôi sử dụng mẫu T4 để tạo lớp ánh xạ.

Pro's - mã có thể đọc được của con người có sẵn tại thời gian biên dịch, nhanh hơn so với người lập bản đồ thời gian chạy. Kiểm soát 100% mã (có thể sử dụng một phần phương thức/mẫu mẫu để mở rộng chức năng trên cơ sở đặc biệt)

Con - loại trừ các thuộc tính nhất định, tập hợp đối tượng miền, v.v., tìm hiểu cú pháp T4.

0

Tôi có thể đề xuất công cụ tôi đã tạo và là nguồn mở được lưu trữ tại CodePlex: EntitiesToDTOs.

Lập bản đồ từ DTO đến Thực thể và ngược lại được thực hiện bằng các phương pháp mở rộng, các phương thức này soạn bên Assembler của mỗi đầu.

Bạn kết thúc với các mã như:

Foo entity = new Foo(); 
FooDTO dto = entity.ToDTO(); 
entity = dto.ToEntity(); 

List<Foo> entityList = new List<Foo>(); 
List<FooDTO> dtoList = entityList.ToDTOs(); 
entityList = dtoList.ToEntities(); 
+0

điều này là sai về mặt kiến ​​trúc bởi vì bạn làm cho DTO và các thực thể miền nhận thức được nhau. – Raffaeu

+5

@Raffaeu Tôi không nghĩ vậy vì phương thức ToDTO/ToDTOs/ToEntity/ToEntities được định nghĩa là các phương thức mở rộng đại diện cho Assemblers. Logic chuyển đổi một thực thể thành một DTO và ngược lại là trong các phương thức mở rộng (Assemblers), chứ không phải trong thực thể Entity/DTO. – kzfabi

+2

Nếu bạn nói về "Assembler", sau đó thực hiện chúng một cách chính xác. Làm cho chúng được mô đun, làm cho chúng dễ dàng thay đổi, sử dụng tiêm phụ thuộc. Không cần chính mô hình miền phải biết về chuyển đổi cho DTO. Giả sử tôi có 1 đối tượng miền nhưng 50 ứng dụng khác nhau sử dụng cùng một tên miền, mỗi ứng dụng có DTO riêng. Bạn sẽ không tạo 50 tiện ích. Thay vào đó, bạn sẽ tạo ra một dịch vụ ứng dụng cho mỗi ứng dụng với (các) trình kết hợp cần thiết được tiêm như một sự phụ thuộc vào dịch vụ. –

1

Làm thế nào để bạn thấy để thực hiện một constructor trong lớp DTO mà mất như một tham số một đối tượng tên miền?

Say ... Một cái gì đó như thế này

class DTO { 

    // attributes 

    public DTO (DomainObject domainObject) { 
      this.prop = domainObject.getProp(); 
    } 

    // methods 
} 
+6

Xin vui lòng, không bao giờ làm điều này. Bạn không muốn lớp DTO của bạn biết hoặc phụ thuộc vào lớp miền của bạn. Ưu điểm của ánh xạ là các lớp thấp hơn có thể dễ dàng được chuyển đổi bằng cách thay đổi ánh xạ hoặc các thay đổi trong lớp thấp hơn có thể là trình điều khiển bằng cách thay đổi ánh xạ. Giả sử dtoA ánh xạ tới domainObjectA ngày hôm nay, nhưng ngày mai yêu cầu là nó ánh xạ tới domainObjectB. Trong trường hợp của bạn, bạn phải sửa đổi đối tượng DTO, một đối tượng không lớn. Bạn đã mất rất nhiều lợi ích của người lập bản đồ. –

+1

Đầu tiên, cảm ơn! : D. Vì vậy, @FrederikPrijck bằng cách chèn một lớp giữa 'DTO' và' DomainObject', về cơ bản chúng tôi cố vấn đề này của DTO phụ thuộc vào đối tượng miền, vì vậy tất cả "công việc xây dựng" được thực hiện trong lớp trung gian (lớp) được gọi là ' mapper', đó là phụ thuộc của cả DTO và DomainObjects. Vì vậy, đó là tốt nhất, hoặc thường khuyên bạn nên, tiếp cận vấn đề này? Tôi chỉ yêu cầu để đảm bảo rằng điểm đã được hiểu. – Victor

+4

Đúng, lớp được gọi là "Assembler". Bằng cách sử dụng lớp thứ 3 để xác định ánh xạ, bạn có thể dễ dàng thay thế lớp lắp ráp bằng cách thực hiện khác (ví dụ: loại bỏ Automapper và sử dụng ánh xạ thủ công), đây luôn là lựa chọn tốt hơn. Cách tốt nhất để hiểu nó là suy nghĩ về nơi tôi sẽ cung cấp cho bạn Object A, và một người khác cung cấp cho bạn Object B. Bạn không có quyền truy cập vào từng đối tượng (chỉ dll), vì vậy việc lập bản đồ chỉ có thể được thực hiện bằng cách tạo ra một thứ 3 lớp. Nhưng ngay cả khi bạn có thể truy cập bất kỳ đối tượng nào, ánh xạ luôn luôn được thực hiện bên ngoài, vì chúng không liên quan. –

0

Tại sao chúng ta không thể làm như thế này?

class UserDTO { 
} 

class AdminDTO { 
} 

class DomainObject { 

// attributes 
public DomainObject(DTO dto) { 
     this.dto = dto; 
}  

// methods 
public function isActive() { 
     return (this.dto.getStatus() == 'ACTIVE') 
} 

public function isModeratorAdmin() { 
     return (this.dto.getAdminRole() == 'moderator') 
} 

} 


userdto = new UserDTO(); 
userdto.setStatus('ACTIVE'); 

obj = new DomainObject(userdto) 
if(obj.isActive()) { 
    //print active 
} 

admindto = new AdminDTO(); 
admindto.setAdminRole('moderator'); 

obj = new DomainObject(admindto) 
if(obj.isModeratorAdmin()) { 
    //print some thing 
} 

@FrederikPrijck (hoặc) ai đó: Xin đề nghị. Trong ví dụ trên, DomainObject phụ thuộc vào DTO. Bằng cách này tôi có thể tránh các mã để làm lập bản đồ dto < -> domainobject.

hoặc lớp DomainObject có thể mở rộng lớp DTO?

Các vấn đề liên quan