2013-07-24 25 views
12

Tôi đang viết một ứng dụng play2.1 với mongodb, và đối tượng mô hình của tôi là một chút mở rộng. khi cập nhật một mục trong DB, tôi cần phải so sánh các đối tượng tạm thời đến từ các hình thức với những gì trong DB, vì vậy tôi có thể xây dựng các truy vấn cập nhật (và đăng nhập các thay đổi).iterate over case class data members

tôi đang tìm kiếm một cách để có tổng thể 2 trường hợp và nhận được sự khác biệt về chúng. iterating trên mỗi thành viên dữ liệu là dài, cứng mã hóa và dễ bị lỗi (nếu a.firstName.equalsIgnoreCase (b.firstName)) vì vậy tôi đang tìm kiếm một cách để lặp qua tất cả các thành viên dữ liệu và so sánh chúng theo chiều ngang (một bản đồ của tên - > giá trị sẽ làm hoặc danh sách tôi có thể tin cậy để liệt kê các thành viên dữ liệu theo cùng một thứ tự mỗi lần).

bất kỳ ý tưởng nào?

case class Customer(
    id: Option[BSONObjectID] = Some(BSONObjectID.generate), 
    firstName: String, 
    middleName: String, 
    lastName: String, 
    address: List[Address], 
    phoneNumbers: List[PhoneNumber], 
    email: String, 
    creationTime: Option[DateTime] = Some(DateTime.now()), 
    lastUpdateTime: Option[DateTime] = Some(DateTime.now()) 
) 

cả ba giải pháp dưới đây là rất lớn, nhưng tôi vẫn không thể có được tên của trường, phải không? đó có nghĩa là tôi có thể ghi lại những thay đổi, nhưng không phải những gì lĩnh vực nó bị ảnh hưởng ...

+0

Bạn có thể đăng một số đoạn mã không? Các trường hợp của bạn, một số trường hợp ví dụ và kết quả bạn muốn đạt được? –

Trả lời

8

Mở rộng trên @ câu trả lời Malte_Schwerhoff, bạn có khả năng có thể tạo ra một phương pháp khác đệ quy mà không chỉ tạo ra các chỉ số của sự khác biệt, nhưng ánh xạ chúng với giá trị mới tại chỉ số đó - hoặc trong trường hợp của các loại sản phẩm lồng nhau, bản đồ về sự khác biệt phụ sản phẩm:

def diff(orig: Product, update: Product): Map[Int, Any] = { 
    assert(orig != null && update != null, "Both products must be non-null") 
    assert(orig.getClass == update.getClass, "Both products must be of the same class") 

    val diffs = for (ix <- 0 until orig.productArity) yield { 
    (orig.productElement(ix), update.productElement(ix)) match { 
     case (s1: String, s2: String) if (!s1.equalsIgnoreCase(s2)) => Some((ix -> s2)) 
     case (s1: String, s2: String) => None 
     case (p1: Product, p2: Product) if (p1 != p2) => Some((ix -> diff(p1, p2))) 
     case (x, y) if (x != y) => Some((ix -> y)) 
     case _ => None 
    } 
    } 

    diffs.flatten.toMap 
} 

Mở rộng trên các trường hợp sử dụng từ câu trả lời rằng:

case class A(x: Int, y: String) 
case class B(a: A, b: AnyRef, c: Any) 

val a1 = A(4, "four") 
val a2 = A(4, "Four") 
val a3 = A(4, "quatre") 
val a4 = A(5, "five") 
val b1 = B(a1, null, 6) 
val b2 = B(a1, null, 7) 
val b3 = B(a2, a2, a2) 
val b4 = B(a4, null, 8) 

println(diff(a1, a2)) // Map() 
println(diff(a1, a3)) // Map(0 -> 5) 
println(diff(a1, a4)) // Map(0 -> 5, 1 -> five) 

println(diff(b1, b2)) // Map(2 -> 7) 
println(diff(b1, b3)) // Map(1 -> A(4,four), 2 -> A(4,four)) 
println(diff(b1, b4)) // Map(0 -> Map(0 -> 5, 1 -> five), 2 -> 8l 
24

lẽ productIterator là những gì bạn muốn:

scala> case class C(x: Int, y: String, z: Char) 
defined class C 

scala> val c1 = C(1, "2", 'c') 
c1: C = C(1,2,c) 

scala> c1.productIterator.toList 
res1: List[Any] = List(1, 2, c) 
5

Bạn có thể sử dụng iterator sản phẩm, và trận đấu trên các yếu tố nếu bạn muốn sử dụng bình đẳng phi tiêu chuẩn như String.equalsIgnoreCase.

def compare(p1: Product, p2: Product): List[Int] = { 
    assert(p1 != null && p2 != null, "Both products must be non-null") 
    assert(p1.getClass == p2.getClass, "Both products must be of the same class") 

    var idx = List[Int]() 

    for (i <- 0 until p1.productArity) { 
    val equal = (p1.productElement(i), p2.productElement(i)) match { 
     case (s1: String, s2: String) => s1.equalsIgnoreCase(s2) 
     case (x, y) => x == y 
    } 

    if (!equal) idx ::= i 
    } 

    idx.reverse 
} 

Sử dụng trường hợp:

case class A(x: Int, y: String) 
case class B(a: A, b: AnyRef, c: Any) 

val a1 = A(4, "four") 
val a2 = A(4, "Four") 
val a3 = A(5, "five") 
val b1 = B(a1, null, 6) 
val b2 = B(a1, null, 7) 
val b3 = B(a2, a2, a2) 

println(compare(a1, a2)) // List() 
println(compare(a1, a3)) // List(0, 1) 

println(compare(b1, b2)) // List(2) 
println(compare(b2, b3)) // List(0, 1, 2) 

// println(compare(a1, b1)) // assertion failed