Bob Horn
Bob Horn

Reputation: 34325

RavenDB - Referencing Properties

In an app on which I'm currently working, I just replaced db4o with RavenDB. I just noticed something that wasn't working, did some research, and now I need a sanity check.

Let's assume this domain model:

Person has Name, Address, and Car properties.

Car has Make, Model, and Mileage properties.

With RavenDB, I can create a Car and save it. Then I can create a Person and assign a Car to the Person's Car property. When I save Person, Car gets saved within Person. All seems fine.

The problem is when I later update Car.Mileage. Car gets updated in RavenDB, but not within Person.Car. Person.Car has the old mileage.

Car exists on its own. Person Joe can own the car, and so can Person Nancy. Both Person objects will have a reference to Car.

In RavenDB, how should this be handled? From everything I've read about aggregate/root objects, it looks like maybe I should add a CarId property to Person. Then, when I load Person, also manually load the Car by the ID. Is that right? Or can I embed the Car property within Person, and somehow have all Person objects show the correct Person.Car.Mileage as Car.Mileage changes over time?

Upvotes: 3

Views: 308

Answers (1)

Alonso Robles
Alonso Robles

Reputation: 401

If I understood your model correctly, you are generating 2 documents like this:

{// cars/1
  "Make": "Honda",
  "Model": "Civic",
  "Mileage": 250000
}

And like this:

{// persons/1
  "Name": "John Doe",
  "Address": "...",
  "Car": {
    "Id": "cars/1",
    "Make": "Honda",
    "Model": "Civic",
    "Mileage": 250000
  }
}

It's important that in this document model. All of the car properties have been denormalized in the Person.Car property. So in your code, when you make an update to Car.Mileage and save it. You end up with the 2 document looking like this:

{// cars/1
  "Make": "Honda",
  "Model": "Civic",
  "Mileage": 999999
}

And like this:

{// persons/1
  "Name": "John Doe",
  "Address": "...",
  "Car": {
    "Id": "cars/1",
    "Make": "Honda",
    "Model": "Civic",
    "Mileage": 250000
  }
}

Which is exactly what you told Raven to do. With this document model, to make sure both documents are consistent you would need to update both the Car object like you did and the Person.Car.Mileage property for all the persons using that car.

Depending on the data access needs you can modify your model in a few different ways. One option is to make your model look like this:

{// cars/1
  "Make": "Honda",
  "Model": "Civic",
  "Mileage": 250000
}

And like this:

{// persons/1
  "Name": "John Doe",
  "Address": "...",
  "Car": "cars/1"
}

With this document model you will only need to update the Car.Mileage property. If you select this option you can also get the referenced document back from Raven in a single network request. By doing something like this:

var person = session.Include<Person>(x => x.Car).Load("persons/1");
var car = session.Load<Car>(person.Car);

But this is only one option in how you can change your document model to address your application's needs.

Upvotes: 2

Related Questions