微软Orleans连接MySQL作为StorageProvider

3 篇文章 0 订阅
1 篇文章 0 订阅

Orleans在Github上提供了不少sample代码,在StorageProvider方面有针对MongoDB,Redis,和SQL Server的,但是可能出于人所皆知的原因吧,没有给出MySQL的示例代码。我摸索了不少时间,尤其Orleans 1.2版本发布后代码写法又有变化(其实变化不大),自己又把代码搞乱掉了,折腾了不少时间,总算通过。

其实Orleans用Mysql做持久化的意义不是很大,就好像ASP.NET大多也是和SQL Server搭配,但是看在$$的份上,我觉得还是用处的。

另外orleans给的SQL Server的例子,是把对象数据都序列化JSON或者BSON再储存到SQL,这我就困惑了,难道现在SQL已经能够做到MongoDB这样的NoSQL数据库了?我记得看过文章好像SQL 2016好像是支持NoSQL了,但真的用起来这么简单么?因为很少用SQL,对SQL很不了解,希望高人指点。


关于Orleans的StorageProvider可以参考微软Orleans官方文档:http://dotnet.github.io/orleans/Getting-Started-With-Orleans/Grain-Persistence


1. 基于Orleans 1.1.3的时候,如果要实现持久化状态,用户的grain首先需要扩展自Grain<T>而不是Grain(例如,PersonState是GrainState的子类)。泛型类Grain<TGrainState>继承自Grain,包含一个State字段,和ReadStateAsync、WriteStateAsync、ClearStateAsync等方法。根据Orleans文档,Grain在激活的时候回自动读取State,但是当State变化的时候,则必须手工显式地实现写入。
Grain state will automatically be read when the grain is activated, but grains are responsible for explicitly triggering the write for any changed grain state as and when necessary.

以Person类为例,
Task IPerson.SetPersonalAttributes(PersonalAttributes props)
        {
            State.FirstName = props.FirstName;
            State.LastName = props.LastName;
            State.Gender = props.Gender;
            return WriteStateAsync();
        }
在设定Person的属性的时候,需要调用一下WriteStateAsync()。

Orleans 1.2版本发布后,不再要求从GrainState扩展,而是可以基于POCO类(就是简单得不能再简单 没有任何引用的class),例如:

namespace QModels.Foundation
{
    /// <summary>
    /// QUser是系统所有用户的基础模型 
    /// </summary>
    public class QUser
    {
        public int ID { get; set; }
        public string Mobile { get; set; }
        public string Name { get; set; }
    }
}
这个解决了我的一个大问题,因为我喜欢把所有的模型都放在一个工程项目里面,然后dll给其它工程引用。按照原来的方式,这个模型库就需要引用orleans,并让所有的类都继承GrainState,而现在就不用这么复杂了,整个结构就干净多了。



2. Grain的实现:

GrainInterface上没有什么变化。这里就掠过了。

实现Grain的时候,在Grain(以Person类为例)的定义之前添加[StorageProvider(ProviderName = "TestStore")]标签,用以指明Person的存储提供器的名称。Orleans 1.2版本后,如果要实现带状态持久化,Grain就要从Grain<T>扩展出去,T可以是POCO风格的简单类,而不必继承GrainState了。

namespace QGrains
{
    [StorageProvider(ProviderName = "mySqlStorage")]
    public class QUserGrain : Grain<QUser>, IQUserGrain
    {
......

StorageProvider的名称由Name标签在服务端siloHost的Configuration文件中指定(不是在Grain实现的工程项目里指定),具体为:

<Provider Type="QMysqlStorage.StorageBase" Name="mySqlStorage"
                ConnectionString="Data Source=10.22.122.222;port=3306;database=orleans;Charset=utf8;Allow Zero Datetime=True;User ID=root;Password=password123123"
                providerName="MySql.Data.MySqlClient"
                UseJsonFormat="both" />
providerName的值为“MySql.Data.MySqlClient”,不确定是否可以随意写,但是MySQL的我就是这么写的,通过了。
“Provider Type”则指向实现StorageProvider的命名空间,本例中是“QMysqlStorage.StorageBase”。



3. Storage Provider的实现:

首先,在这个工程项目中要安装Mysql.Data, Mysql.Data.Entity.EF6, MySQL.Web等几个插件,可以用NuGet安装。


Provider需要添加IStorageProvider接口,并实现包含ReadStateAsync、WriteStateAsync、ClearStateAsync等接口成员,以及Init、Close等初始化和收尾的方法。

namespace QMysqlStorage{
public class StorageBase : IStorageProvider
{
.....
}}
Orleans 1.2版本以后,ReadStateAsync等接口有所变化,原来是Task ReadStateAsync(string grainType, GrainReference grainReference, GrainState grainState),现在第三个参数改为接口注入Task ReadStateAsync(string grainType, GrainReference grainReference, IGrainState grainState),这样grainState参数就带了一个State字段,其实就是模型的实例数据了。

public async Task ReadStateAsync(string grainType, GrainReference grainReference, IGrainState grainState)
        {
            int primaryKey =(int) grainReference.GetPrimaryKeyLong();
            using (var db= new QDbContext(connectionString))
            {
                grainState.State =  db.qusers.Find(primaryKey);
                grainState.ETag = Guid.NewGuid().ToString();
            }  }     

注意我这里把原来Orleans官方例子中KeyValueStore的方式删除了,还是使用表方式实现存储,为的是后续通过我比较熟悉的Sql Query做查询。


4. 如果用EF实现ORM,则要给StorageProvider中dBContext加上标签:
[DbConfigurationType(typeof(MySqlEFConfiguration))]

namespace QMysqlStorage
{
    //[DbConfigurationType(typeof(KeyValueDbConfiguration))] //这是原来针对SQL Server存储层的标签
    [DbConfigurationType(typeof(MySqlEFConfiguration))]
    public class QDbContext : System.Data.Entity.DbContext
    {
        public QDbContext(string connString) : base(connString)
        {
            Database.SetInitializer<QDbContext>(new MysqlInitializer(connString));
        }

        public DbSet<QUser> qusers { get; set; }
    }
}

DbContext可以指定一个初始化器,这里是MysqlInitializer。




基本上这样就可以实现Orleans基于MySQL的持久化了。



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值