2009-05-13 25 views
16

Tại sao OK được có trường Id trong các thực thể miền? Tôi đã thấy một số giải pháp cung cấp lớp cơ sở với Id và Id GetHashCode dựa trên Id và Id.DDD: Các khóa chính (Id) và ORM (ví dụ: NHibernate)

Sự hiểu biết của tôi về mô hình miền là nó chỉ nên chứa những thứ liên quan đến miền. Mặc dù trong các trường hợp hiếm hoi (các lệnh có thể theo dõi) Các Id có ý nghĩa, hầu hết thời gian chúng không cung cấp bất cứ điều gì ngoại trừ một cách đơn giản để tham chiếu các đối tượng trong DB/trên giao diện người dùng.

Tôi không thấy lợi ích Bằng/GetHashCode, do việc thực hiện Bản đồ danh tính phải đảm bảo rằng bình đẳng tham chiếu bình đẳng id.

Kỳ lạ thay, tôi không thể dễ dàng tìm thấy những gì người khác nghĩ về chủ đề này, vì vậy tôi hỏi nó ở đây. Ý kiến ​​chung về việc sử dụng các Id liên quan đến tên miền trong các thực thể miền là gì? Và có bất kỳ vấn đề với NHibernate nếu tôi không thêm Id để thực thể miền của tôi?

UPDATE:

Cảm ơn câu trả lời.

Một số người trong số họ cho rằng có Id là cách duy nhất để ORM thực hiện cập nhật DB. Tôi không nghĩ rằng đây là trường hợp. ORM đã theo dõi tất cả các thực thể được tải từ DB, vì vậy bạn có thể dễ dàng nhận được một Id nội bộ khi cần.

UPDATE 2:

trả lời để Công lý và quan điểm tương tự: gì nếu chúng ta có một ứng dụng web và cần một cách để tham khảo các thực thể giữa phiên? Giống như chỉnh sửa/tài nguyên/id?

Vâng, tôi thấy điều này là nhu cầu cụ thể của giao diện người dùng/môi trường bị ràng buộc, không phải mô hình miền cần. Có một dịch vụ ứng dụng hoặc kho lưu trữ với phương thức GetIdentitity (nhất quán với phương thức Load (nhận dạng)) có vẻ là đủ cho kịch bản này.

+1

Bạn sẽ triển khai GetIdentity như thế nào nếu bạn không có số nhận dạng? Bạn sẽ nhận được đối tượng từ máy khách và bạn phải tra cứu danh tính. Làm thế nào bạn sẽ tìm thấy nó? Nội dung của đối tượng có thể đã được thay đổi trên máy khách. Bạn sẽ không tìm thấy nó nữa. Tôi cũng trả lời các bình luận của bạn cho câu trả lời của tôi. –

+0

Tôi không đề cập đến thực tế khi tôi nhận được một đối tượng từ khách hàng. Trong trường hợp này tôi có thể nhận được một số DTO có một Id (và điều này là có liên quan ngay cả khi tôi không có một DB và lưu trữ tất cả mọi thứ trong bộ nhớ, trong trường hợp này Id trong DTO có thể là một chìa khóa trong một số Hashtable bên trong). Nhưng trước khi gửi đối tượng cho khách hàng, tôi có thể nhận được một Id và thêm nó vào DTO tôi đang gửi. Hoặc chỉ cần gửi một Id trong một số trường hợp. –

+0

Tôi chỉ tìm thấy trong các tài liệu NH mà NH không cần một tài sản id! Xem câu trả lời của tôi, tôi đã thêm một phần. –

Trả lời

4

Tôi chỉ có thể nói về NHibernate. Ở đó bạn cần một trường cho khóa chính, tùy thuộc vào bạn nếu bạn lấy dữ liệu nghiệp vụ (không được khuyến nghị) hoặc khóa thay thế không có ý nghĩa kinh doanh.

kịch bản điển hình là:

  • auto-incrementing giá trị được tạo ra bởi các cơ sở dữ liệu
  • guid tạo ra bởi NHibernate
  • guid tạo ra bởi các logic kinh doanh

Có một lợi thế lớn để có một id duy nhất. Khi bạn truyền đối tượng của mình xung quanh, ví dụ cho máy khách và quay lại máy chủ, bạn không thể dựa vào nhận dạng bộ nhớ. Bạn thậm chí có thể có nhiều trường hợp trong bộ nhớ của cùng một cá thể nghiệp vụ. Ví dụ nghiệp vụ được xác định bởi id.

So sánh dựa trên id là vấn đề về hương vị. Cá nhân tôi thích mã đơn giản và đáng tin cậy và so sánh dựa trên id đơn giản và đáng tin cậy, trong khi so sánh sâu luôn có một chút rủi ro, dễ bị lỗi, không thể duy trì. Vì vậy, bạn kết thúc với toán tử == so sánh danh tính bộ nhớ và bằng so sánh danh tính doanh nghiệp (và cơ sở dữ liệu).

NHibernate là cách ít xâm nhập để ánh xạ một mô hình lớp tới cơ sở dữ liệu quan hệ mà tôi biết. Trong dự án lớn của chúng tôi, chúng tôi có các khóa chính và thuộc tính phiên bản (chúng được sử dụng để khóa lạc quan). Bạn có thể tranh luận rằng điều này là xâm nhập, bởi vì nó không được sử dụng cho logic kinh doanh.

NH không yêu cầu phải có các thuộc tính này. (tuy nhiên nó cần một trong các thuộc tính như khóa chính.) Nhưng hãy xem xét:

  • Nó hoạt động tốt hơn, ví dụ:khóa bi quan chỉ có thể với thuộc tính thích hợp,
  • nhanh hơn: int id hoạt động tốt hơn trên nhiều cơ sở dữ liệu, sau đó các loại dữ liệu khác
  • và dễ dàng hơn: lấy tài sản có ý nghĩa với doanh nghiệp bị khuyến khích vì nhiều lý do.

Vậy tại sao cuộc sống của bạn khó khăn hơn mức cần thiết?


Edit: Chỉ cần đọc the documentation và thấy rằng NHibernate không không cần một tài sản id trong lớp dai dẳng! Nếu bạn không có thụt lề, you can't use some features. Đó là khuyến cáo để có nó, nó chỉ làm cho cuộc sống của bạn dễ dàng hơn.

+1

Việc truyền máy khách-máy chủ là một trường hợp sử dụng cụ thể - nó có thể giải quyết bằng cách có một nhà cung cấp nhận dạng hoặc các phương thức lưu trữ được sử dụng cho trường hợp cụ thể này (GetId (đối tượng), GetById (id)). Ngoài ra, tôi không thấy sự khác biệt giữa nhận dạng bộ nhớ và danh tính doanh nghiệp nếu chúng tôi sử dụng ORM. Theo như tôi hiểu, trong một phiên sẽ luôn có một đối tượng duy nhất với một Id đã cho (ngoại trừ các phép chiếu, nhưng đây không phải là điều thú vị để so sánh). –

+2

Tôi thấy quan điểm của bạn tại sao khóa dữ liệu kinh doanh không được khuyến khích, nhưng câu hỏi ban đầu của tôi là sử dụng khóa thay thế - nhưng chỉ trong DB, nơi nó thuộc về. Vì vậy, các nhược điểm không nên áp dụng nếu NHibernate biết khóa DB thay thế - Tôi chỉ không muốn xác định nó trong các thực thể miền của tôi. –

+0

Ý của bạn là: NẾU bạn không có ứng dụng máy khách-khách hàng, VÀ không bao giờ phải truyền các đối tượng từ phiên này sang phiên khác (ví dụ: chuyển qua thời gian, mạng, tệp) VÀ không cần nhận dạng doanh nghiệp thay thế, THEN có thể NHibernate quản lý khóa cơ sở dữ liệu chính trong nội bộ. Điều này có lẽ đúng, nhưng đây sẽ là một trường hợp rất hiếm với những hạn chế mạnh mẽ tự nhiên. Bạn có thể đề xuất điều này như là tính năng nâng cao trong Jiber của NHibernate. Hoặc thực hiện nó như một bản vá. –

0

Bạn phải có cách này hay cách khác để ORM có thể quay lại cơ sở dữ liệu để thực hiện cập nhật; Tôi đoán nó có thể là riêng tư và ẩn trong một lớp cơ sở nhưng loại đó vi phạm khái niệm POCO.

+0

Xem bài đăng cập nhật, tôi nghĩ rằng ORM biết Id anyway, nó chỉ có thể sử dụng Bản đồ nhận dạng ngược lại. –

+0

Bạn đang nói rằng ORM theo dõi tất cả các đối tượng hiện có trong hệ thống? Tôi không thể nói một thực tế nhưng nó cảm thấy khó xảy ra. –

+0

Trong một phiên, có, nó nên. Tùy thuộc vào cấu hình, phiên có thể là yêu cầu web hoặc thậm chí toàn bộ chuỗi hoặc thời gian của ứng dụng. Lý do là khi bạn gọi SubmitChanges nó phải biết những thay đổi ở đâu. Và AFAIK hầu hết ORM thực hiện http://martinfowler.com/eaaCatalog/identityMap.html cũng có nghĩa là họ phải biết những gì họ đã có. –

0

giả định rằng id của bạn là khóa chính, bạn sẽ không thể lưu bất kỳ dữ liệu nào trở lại DB mà không có nó.
Theo như bằng và GetHashCode đi, đây là để đặt hàng trong Danh sách nơi bạn tạo một thứ tự tùy chỉnh.

Cảm ơn câu trả lời.

Một số người trong số họ cho rằng có Id là cách duy nhất để ORM thực hiện cập nhật DB. Tôi không nghĩ rằng đây là trường hợp. ORM đã theo dõi tất cả các thực thể được tải từ DB, vì vậy bạn có thể dễ dàng nhận được một Id nội bộ khi cần.

Tôi sẽ rất ngạc nhiên nếu điều đó xảy ra. Thông thường nó tạo ra một lệnh chèn chỉ từ các thuộc tính mà bạn đã xác định.

+0

Xem bài đăng cập nhật, tôi nghĩ ORM biết Id nội bộ. –

+0

Tôi sẽ rất ngạc nhiên nếu đó là trường hợp. Thông thường nó tạo ra một lệnh chèn chỉ từ các thuộc tính mà bạn đã xác định. Có, bởi vì trong hầu hết các trường hợp, điều đó có ý nghĩa. Tuy nhiên, một ORM tốt cũng có phiên bản trước của đối tượng của bạn và nói chung có thể lưu trữ càng nhiều thông tin về đối tượng của bạn như nó muốn. Tôi vừa googled một ví dụ về cách bổ sung dữ liệu có thể được thêm vào một chèn: http://www.dav-evans.com/?p=75. –

0

Không có tùy chọn nào khác để nhận cùng một đối tượng không có nhận dạng.Ví dụ, mọi người có số an sinh xã hội hoặc mã cá nhân hoặc thứ gì đó duy nhất và chúng tôi có thể xác định chúng bằng nó.

Bạn có thể sử dụng danh tính tự nhiên nhưng đó là lỗi dễ xảy ra.

Chỉ cần đổi tên Id thành Danh tính. Nó trông đẹp hơn trong mô hình miền.

Thực thể được gọi là thực thể vì chúng có nhận dạng.

+0

Đối với các tình huống Web và các trường hợp tương tự khác, một số loại IIdentityService thực sự có thể là NHibernateIdentityService sẽ là đủ (nhưng nó là trường hợp cụ thể khi bạn muốn tham khảo một số đối tượng cụ thể để truy xuất trong tương lai, chứ không phải chung cho mô hình miền). –

0

Tôi thường bao gồm Id trong miền làm lớp Cơ sở thực thể. Tôi không biết cách nào khác để sử dụng ORM.

Một đối tượng trong miền đã là duy nhất theo tham chiếu của nó, sử dụng id để xác định tính độc đáo/bình đẳng thực sự không khác nhau trong thực tế. Tôi đã không gặp phải một tác dụng phụ nghiêm trọng cho cách tiếp cận này cho đến nay.

-1

Bạn cũng có thể sử dụng nhiều trường để thiết lập danh tính, được gọi là các phím tổng hợp. Tuy nhiên, điều này sẽ đòi hỏi nhiều công việc hơn cho bạn.

Tìm hiểu về chúng here

+0

Điều đó có nghĩa là tôi sẽ phải có cùng một khóa chính trong bảng? –

+0

Vâng, vâng, danh tính trong nhib cần phải là danh tính trong db .. đó là loại điểm .. –

1

Trong Nh, bạn không thể sử dụng bình đẳng tham chiếu cho các trường hợp tách rời. Điều này khiến bạn sử dụng NH trong các khách hàng muốn sử dụng hành vi này (theo ý kiến ​​của tôi đây là hành vi đúng, NH không phụ thuộc vào phép thuật!).

Trong các ứng dụng web hoặc tập quán dựa trên phiên mà bạn có thể vào db trong phạm vi của một ISession, tôi nghĩ rằng tôi đúng khi nói rằng bạn có thể dựa vào sự bình đẳng tham chiếu. Nhưng trong một kịch bản khách hàng thông minh, hoặc cụ thể hơn, bất kỳ kịch bản nào trong đó hai Phiên làm việc đang chia sẻ một cá thể (một được nạp từ hoặc được chèn vào db, sau đó được chuyển đến thứ hai), bạn cần (các) trường id db được lưu trữ cùng với ví dụ.

phiên thứ hai bên dưới sẽ không có ý tưởng rằng trường hợp đang được chuyển đi đã được chèn và yêu cầu cập nhật và thậm chí nếu bạn đã thay đổi bản cập nhật, tôi cho rằng tôi đang nghĩ rằng nó sẽ không để biết ID DB của lớp.

class SomeEntityWithNoId 
{ 
public blah etc {} 
} 

class dao 
{ 

void DateMethod() 
{ 
var s1 = sessionFactory.OpenSession(); 
var instance = new SomeEntityWithNoId(); 
instance.Blah = "First time, you need to insert"; 
s1.Save(s1); //now instance is persisted, has a DB ID such as identity or Hilo or whatever 
s1.close(); 
var s2 = sessionFactory.OpenSession(); 
s2.Blah = "Now update, going to find that pretty hard as the 2nd session won't know what ID to use for the UPDATE statement"; 

s2.Update(instance); //results in boom! exception, the second session has no idea *how* to update this instance. 




} 
} 

Nếu bạn lo lắng về trường ID (s), mà bạn là chính xác trong suy nghĩ phần lớn là vô dụng cho bất cứ điều gì khác hơn là mối quan tâm kiên trì, bạn có thể làm cho họ tin, vì vậy ít nhất hành vi này và ngữ nghĩa được đóng gói . Bạn có thể thấy rằng cách tiếp cận này đặt một số ma sát vào TDD.

Tôi nghĩ bạn chính xác về các bản đồ ID liên quan đến NH ít nhất. Nếu cá thể là thoáng qua khi nó được đính kèm lần đầu tiên vào phiên, kiểu của bạn không cần phải lưu trữ ID db của nó trong một trường. Tôi nghĩ rằng phiên sẽ biết cách quản lý mối quan hệ của nó với db. Tôi chắc chắn bạn có thể phá vỡ thử nghiệm để chứng minh hành vi này, p

+0

Tôi đồng ý với bài đăng của bạn, nhưng tôi không nghĩ rằng ví dụ được cung cấp (2 phiên tiếp theo với một đối tượng) một trường hợp sử dụng phổ biến cho NHibernate. Gửi các đối tượng từ máy chủ đến máy khách là một câu chuyện khác, nhưng trong trường hợp này chúng có thể là DTO hoặc có một bộ nối tiếp tùy chỉnh cho phép Id được gửi/nhận. –

3

Thông thường, bạn sẽ không có một mô hình tên miền thực sự. Bạn sẽ có vô số phiên đồng thời và tuần tự, mà phải được phối hợp, và mỗi phiên chứa trong nó mô hình miền thu nhỏ, cô lập, giao dịch riêng của nó. Bạn sẽ không có cùng một thể hiện đối tượng giữa hai đồng thời hoặc giữa hai phiên tuần tự. Nhưng bạn sẽ cần một số cách để đảm bảo rằng bạn có thể di chuyển thông tin từ phiên này sang phiên khác.

Ví dụ, tất nhiên, là một cặp/resource/list và/resource/show/id của URL (tương ứng với một cặp hành động điều khiển thích hợp trong asp.net mvc). Di chuyển từ một đến khác, có hai phiên hoàn toàn độc lập, nhưng họ cần phải giao tiếp (thông qua HTTP và trình duyệt) với nhau.

Ngay cả khi không sử dụng cơ sở dữ liệu, đối tượng mô hình miền của bạn sẽ vẫn còn cần một số biểu mẫu nhận dạng vì bạn vẫn sẽ có nhiều mô hình tên miền thu nhỏ, không bị cô lập; và bạn sẽ có tất cả các mô hình miền này trong các phiên độc lập cả hai cùng một lúc và cái khác.

Mẫu đối tượng không đủ, bởi vì đối tượng không giống nhau giữa các phiên mặc dù các thực thể khái niệm cơ bản mà chúng đại diện là cùng một thực thể.

+2

Cảm ơn điểm được mô tả kỹ lưỡng. Xem bài viết cập nhật 2. Tôi đồng ý rằng bạn cần một hệ thống tham chiếu/nhận dạng có thể tuần tự hóa nếu bạn muốn làm/resource/show/id, nhưng nó có vẻ như một ràng buộc cụ thể về Web, không phải là yêu cầu miền. Nhưng đối với sự bình đẳng, có vẻ như với tôi rằng có một lý do để so sánh các đối tượng từ các phiên khác nhau. –

+0

Mẫu đơn vị công việc hoặc phiên làm việc sẽ yêu cầu, ngay cả trong ứng dụng dành cho máy tính để bàn mà không có cơ sở dữ liệu, đối tượng mô hình miền của bạn có số nhận dạng liên tục duy nhất giống nhau trên các phiên, mặc dù các đối tượng không giống nhau trên các phiên. – yfeldblum

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