I want to detach some entities from session and cache them in ASP.net web cache. The cached entities aren't editable by users hence do not need to attach back to a new session.

What is the easiest way to accomplish the task?? The disconnected state is not easy to work with, and disconnect everything within the transaction scope. And there is no easy way like LightSpeed ORM which has the .AsDto() extension method..... :x


Updated at 09.04.2010 3:26:11

I am planning to use DO in ASP.net projects in the future.

There are 2 types of caching I have in mind.

One is 'global caching' So, when the application starts, I will initialize the Domain and then fetch some frequently used result sets and cache them in memory. This includes the sitemap (we are using custom SQL sitemap provider), items featured on the home page etc.

I prefer to cache this type of data in WeakReference. When the data is changed by admin, the old cache is purged explicitly and replaced by fresh copy of data. Otherwise, the result sets always stay in memory as long as the AppDomain is alive.

Another type of caching is 'per user caching'. This will include things like shopping cart, and user preferences etc.

I prefer to cache this data in in proc session state or ASP.net cache. Since data like shopping cart will change frequently and is editable,cached entities must be capable to merge back to session and persist to database at some points.

DevExpress XPO has a property to turn a XPCollection<t> into WeakReference result set, unfortunately XPCollection is always attach to a session, hence a connection is always open while the collection stays alive.

LightSpeed allows us to specify an attribute and it will automatically store the result set in ASP.net Cache, when fetching data it looks at the cache first before making another DB roundtrip, and also, as I mentioned, it has AsDto() extension method to make my life easier.

As for DO, I don't like the DisconnectedState and O2O mapper API. I mean, it should be easier. The only tool that is doing Detach / Attach really good is WCF RIA Services. When the detach entities are in Silverlight app, change tracking and validation are still working, and merge back at server side correctly. However, this is achieved by code generating separate set of classes that match the domain model.


Updated at 09.04.2010 12:51:53

If the caching API is using ASP.net cache, it is better to implement the whole caching API in separate assembly. This is because .Net 3.5 or 4 Client Profile does not have System.Web.dll. A dependency on System.Web will force developer making a choice whether to ditch DO or use the full framework when developing WinClient app.

Although caching API is a nice feature to have, it must be generic enough to be useful. Some people relies on ASP.net cache / session, and others might use Velocity, memcache or some other 3rd party components. I suppose this isn't easy to implement, and will take quite some times to deliver it. So, I think the simplified conversion API should be the top priority.

entity.TransformTo<entitydto>() will be even better if it can transform the prefetch object graphs too.

This thread was imported from our support forum. The original discussion may contain more detailed answer. Original topic by ccchai.

asked Apr 08 '10 at 06:51

Editor's gravatar image

Editor
46154156157


One Answer:

Likely, the most obvious one is to write your own DTOs using the following pattern for conversion:

  • Constructor accepting optional source parameter performing conversion of entity to DTO.

  • virtual ApplyChanges method assigns all the values to underlying Entity.

Simplest example of this case is PersonEditModel type from new ASP.NET MVC sample - but during the nearest day I'm going to extend it to show more complex scenarios.

Pros: simplicity; works well for entities with small count of fields & relationships to process. Cons: requires manual tuning of conversion code after any changes to either entity or DTO; applying the changes made to collections (if this is necessary - normally this isn't handled this way) must be pretty complex (requires comparison with an old copy).

Another alternative is usage of our object-to-object mapper. It automates both forward and backward conversion, so in future it must be simply ideal solution in such cases. But there are two big cons:

Finally, it must be a good idea to provide simplified API like this:

var mapping = new Mapping()
  .Map(typeof(PersonDto), typeof(AddressDto)) // Conventional mapping
  .Map<Customer>().To(CustomerDto) // Fluent mapping
    .With(c => c.Company.Name, dc => dc.CompanyName)
    .With(...)
  .Done();
mapper = new Mapper(mapping);
// mapper = new Mapper(typeof(PersonDto), typeof(AddressDto), ...) - shortcut for conventional mapping
// mapper = Mapper.Get<PersonDto>(typeof(OtderDto1), ...) - shortcut for getting default conventional mapper (must be cached). 
// Since they're thread safe, this should work well.

...
// Creating DTOs
var dtoGraph = mapper.Transform(entityGraph);

...
// Applying the changes
mapper.Compare(originalDtoGraph, newDtoGraph).Operations.Replay();

// Finally, we can implement simplified conversion to DTOs using default conventional mapper:
var personDto = Mapper.Transform<PersonDto>(person); // or using a shortcut for persistent objects: person.Transform<PersonDto>()

Unfortunately, this is only an example showing how this part could work. Current API is much less attractive...


Forgot to ask: what is the final goal of conversion to DTO in your case?

E.g. if you need this to mainly cache something (you said you don't want to modify the DTO), we may talk about caching API. It is also in plans, so getting any exact requirements would be great.


I thought pretty long on this. For now I recommend you to do not optimize for caching scenarios. We're planning to implement caching support in DataObjects.Net, and, when it's done, you'll get layered caches and declarative semantic for managing them; scenarios we're going to cover include as Entity, EntitySet and query result caching.

The only reason for postponing caching implementation was absence of real customer requests related to this.

In cases when caching API won't suit well, the following options will be available: 1) Simplified conversion API relying on O2O mapper: entity.TransformTo<entitydto>(), entity.ApplyChangesFrom<entitydto>(original, current). Must work well in almost all the cases except 2) 2) DisconnectedState. Good for implementing long-running transactions. Must be extended to allow explicit content inclusion / exclusion, and obviously, we must simplify its usage in web applications (currently it's pretty complex, especially in conjunction with SessionManager). That's what I'm going to do on the next week.


> So, I think the simplified conversion API should be the top priority.

Yes - we'd deefinitely deliver an open caching provider API first, + few actual providers (e.g. for ASP.NET cache).

> entity.TransformTo<entitydto>() will be even better if it can transform the prefetch object graphs too.

Specifying the boundaries of graph to transform is definitely a pretty complex problem. Agree, prefetch API might help here - I'll return back to this question when we'll start working on improvement of this feature.

answered Apr 08 '10 at 18:30

Alex%20Yakunin's gravatar image

Alex Yakunin
29714412

Seconding this feature. We also need smth like this.

(Apr 08 '10 at 18:30) xumix xumix's gravatar image
Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!
toggle preview

Subscription:

Once you sign in you will be able to subscribe for any updates here

Tags:

×573

Asked: Apr 08 '10 at 06:51

Seen: 24,710 times

Last updated: Apr 08 '10 at 06:51

powered by OSQA