OrleansContrib/Orleans.Providers.EntityFramework

[Question] Support for actors that are stored as collections

Closed this issue · 2 comments

Hello. First things first: Thank you for your time and work, it's an excellent project!

Could you please clarify if it's currently possible to store a collection, for example, Grain<List<T>>? I'm looking for a way to implement an actor that would serve as a read-only cache for the whole (already existing) database table, not the single row.

I probably can achieve my goal by injecting the Entity context into the actor directly, but it would be cool to be able to depend on 'ReadStateAsync()` functionality. Btw if it's impossible now, but you think it's a feature that would be beneficial to the project, could you please provide some guidance on how to better implement it?

Hi, and thanks!

No, it only works for single instances of entities.

I don't think supporting collection caching would fit well here as there are quite a few challenging issues regarding caching collections. A few of which comes to my mind right away are Invalidation (something more sophisticated than time-based expiration), performance (A collection grain can quickly become a bottleneck for example) and constructing the cache itself. The actual code needed is mostly unrelated to storage and the storage part can be easily get abstracted away.

However, I have written something like that with Orleans before. It did fit our needs but it can be done with much better performance with other solutions (e.g. Redis), so get to know your needs first.

but it would be cool to be able to depend on 'ReadStateAsync()` functionality.

I'm not sure you can get far using stateful grains, as the ReadStateAsync interface wouldn't get you anything other than the grain reference which is pretty much useless for constructing a complex query.
also, If you end up using the context in the grain just don't inject it in the grain that would keep the context alive as long as the grain lifetime.

@alirezajm sure, I'm not going to inject the context itself. I guess I'd go with injecting something like IExternalDatabaseContextFactory which I'll then use to get a disposable short living Entity context by external system's key =)
It happens so that I need to access a few external systems with different databases in a way I described, so I guess for now it would work.

Of course it would be smarter to use some in-memory solution for caching or hide the databases behind a friendly non-Orleans API, but it's not an option for me for non-technical reasons, so I decided to go with a dirty solution (this particular part is not performance critical).

Thanks for your swift response.