Live transformation question

51 views
Skip to first unread message

Niclas Emdelius

unread,
Jun 17, 2013, 8:19:44 AM6/17/13
to rav...@googlegroups.com
Hi,

I use Raven to store orders. In the order document I want all the original product details for tracking purposes.

The product objects are basically a proxy for an external object. When I read back orders I want them in a simple View object rather in their original form.

The test code below works, but it it feels it could be made in a simpler way?

In the index' TransformResult the Order is converted into an anonymous type, when I already have a type for OrderViewModel. And why do I need a index at all? 

Anyone that could give me a few hints?

Thanks

----

public class Order
{
public Guid Guid;
public IEnumerable<OrderRow> OrderRows { get; set; }
}
public class OrderViewModel
{
public Guid Guid;
public IEnumerable<OrderRowViewModel> OrderRows { get; set; }
}

public class OrderRow
{
public IProduct Product;
}

public class OrderRowViewModel
{
public ProductViewModel Product;
}

public interface IProduct
{
string DisplayName { get; }
}

public class VeryComplicatedProductInstance : IProduct
{
public string DisplayName { get { return "Product Name"; } }
}

public class ProductViewModel 
{
public string DisplayName { get; set; }
}


[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var documentStore = new DocumentStore { Url = "http://localhost:99", DefaultDatabase = "test" };
documentStore.Initialize();
IndexCreation.CreateIndexes(typeof(Order_ById).Assembly, documentStore);     

var orderId = Guid.NewGuid();
var order = new Order
{
Guid = orderId,
OrderRows = new[]
{
new OrderRow {Product = new VeryComplicatedProductInstance()}
}
};


using (var session = documentStore.OpenSession())
{
session.Store(order, order.Guid.ToString());
session.SaveChanges();
}

OrderViewModel loadedOrder;
using (var session = documentStore.OpenSession())
{
loadedOrder = session.Query<Order, Order_ById>()
.Where(o => o.Guid == orderId)
.OfType<OrderViewModel>()
.FirstOrDefault();
}

Assert.IsNotNull(loadedOrder);
Assert.IsNotInstanceOfType(loadedOrder.OrderRows.First().Product, typeof(VeryComplicatedProductInstance));
Assert.IsInstanceOfType(loadedOrder.OrderRows.First().Product, typeof(ProductViewModel));
Assert.AreEqual("Product Name", loadedOrder.OrderRows.First().Product.DisplayName);

}
}

public class Order_ById: AbstractIndexCreationTask<Order>
{
public Order_ById()
{
Map = orders => from order in orders
                 select new { order.Guid, order.OrderRows};

TransformResults = (database, results) => from order in results
 select new
 {
 order.Guid,
 OrderRows = order.OrderRows.Select(or=>new 
 {
 Product = new {
 DisplayName = or.Product.DisplayName
 }
 })  
 };
}
}

Oren Eini (Ayende Rahien)

unread,
Jun 18, 2013, 3:37:02 AM6/18/13
to ravendb
If you need just the display name, why are you storing the full thing?



--
You received this message because you are subscribed to the Google Groups "ravendb" group.
To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Niclas Emdelius

unread,
Jun 19, 2013, 7:58:18 AM6/19/13
to rav...@googlegroups.com
Hi,

This is just an example. I need lots of other fields as well and that is why I'm asking if there is another way to do it. 
As I've done now I have to make sure the index' TransformResult matches the field names in ProductViewModel, and it won't give me a compile time error if they don't.

As it is orders I'm storing I also need to store as much info as possible in the event of post mortem debug analysis, such as how the product's prices was calculated and stuff like that.

/Niclas

Oren Eini (Ayende Rahien)

unread,
Jun 19, 2013, 3:34:23 PM6/19/13
to ravendb
You are mixing a lot of different concerns here.

Then you want to pull data from other documents, which is Immediate Reference.


Niclas Emdelius

unread,
Jun 20, 2013, 2:39:44 AM6/20/13
to rav...@googlegroups.com
No, I think you misunderstand me. I don't want to pull data from other documents, just a single document which contains all data I need, (and more).

What I'd like to do is use one type for creating a document, and then load the document into another type (simpler) with the same field names.

Thanks

Oren Eini (Ayende Rahien)

unread,
Jun 20, 2013, 2:42:14 AM6/20/13
to ravendb
Load the document in your client app, then transfrom it in your code

Niclas Emdelius

unread,
Jun 20, 2013, 2:49:40 AM6/20/13
to rav...@googlegroups.com
How do I load a document without deserializing into a type?

Oren Eini (Ayende Rahien)

unread,
Jun 20, 2013, 2:54:52 AM6/20/13
to ravendb
No, load it into the doc type, then transform it.

Niclas Emdelius

unread,
Jun 20, 2013, 3:00:20 AM6/20/13
to rav...@googlegroups.com
How do I load it into the "doc type"? 

Very interesting re result transformers!

Oren Eini (Ayende Rahien)

unread,
Jun 20, 2013, 3:13:54 AM6/20/13
to ravendb
session.Load<YourType>(docId);

Niclas Emdelius

unread,
Jun 20, 2013, 3:34:00 AM6/20/13
to rav...@googlegroups.com
The problem is that I can't deserialize into the original product type. 

session.Load<OrderViewModel>(orderId) doesn't work (invalid cast exception)

Is it possible to retrieve the document in a untyped format (dictionaries?) and handle the deserialization myself?

Anyway, I think I'll solve it with result transformers. 
Thanks!

Mauro Servienti

unread,
Jun 20, 2013, 4:12:48 AM6/20/13
to rav...@googlegroups.com

Have you tried, just guessing, something like:

 

session.Load<RavenJObject>( yourId );

Niclas Emdelius

unread,
Jun 20, 2013, 4:18:42 AM6/20/13
to rav...@googlegroups.com
Yes it works! Thanks!

To unsubscribe from this group and stop receiving emails from it, send an email to ravendb+unsubscribe@googlegroups.com.

Reply all
Reply to author
Forward
0 new messages