无论如何,要为Memcached序列化linq对象吗? [英] Is there anyway to serilize linq object for Memcached?

查看:75
本文介绍了无论如何,要为Memcached序列化linq对象吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚开始切换到memcached,目前正在使用memcached进行测试.

我有2个对象,我创建了一个对象,并在其上放置了[Serializable](例如,让它称为Object1),另一个对象是使用Linq DBML(Object2)创建的..

我尝试过memcached List<Object1>,它工作得很好,就像魅力一样,这里的所有内容都已缓存并正确加载.

但是随后,我继续使用Linq对象,现在我尝试将其添加到memcached中.List<Object2>这是行不通的,它根本没有添加到memcached中.没有添加密钥

我继续前进,将序列化模式更改为单向",再次执行添加操作,仍然没有希望.

反正有这项工作吗?

这是我刚刚编写的简单测试,使用了来自Codeplex的MemcachedProvider进行演示:

public ActionResult Test()
{
    var returnObj = DistCache.Get<List<Post>>("testKey");
    if (returnObj == null)
    {
        DataContext _db = new DataContext();
        returnObj = _db.Posts.ToList();
        DistCache.Add("testKey", returnObj, new TimeSpan(29, 0, 0, 0));
        _db.Dispose();
    }

    return Content(returnObj.First().TITLE);
}

这是来自Memcached的,没有调用STORE:

> NOT FOUND _x_testKey
>532 END
<528 get _x_testKey
> NOT FOUND _x_testKey
>528 END
<516 get _x_testKey
> NOT FOUND _x_testKey
>516 END

在我的SQL事件探查器中,它调用3查询进行3个测试时间=>证明从Memcached回调的对象为null,然后进行查询.

解决方案

看起来默认的实现(DefaultTranscoder)是使用BinaryFormatter; 单向"内容是对其他序列化器(DataContractSerializer)的指令,并且不会添加[Serializable].

(注意:我为自己添加了备忘录尝试为memcached编写一个protobuf-net转码器;这很酷,并且将免费修复其中的大部分内容)

我还没有测试,但是有一些选择可以解决:

  1. 编写一个不同的代码转换器实现,该实现可检测到[DataContract]并使用DataContractSerializer,并挂接该代码转换器
  2. 通过局部类将[Serializable]添加到您的类型中(由于LINQ字段类型不可序列化,我不相信这会起作用)
  3. 在使用DataContractSerializer
  4. 的部分类中添加ISerializable实现
  5. 类似于3,但使用protobuf-net,其中a:与单向"一起使用,而b:比DataContractSerializer更快且更小
  6. 编写可序列化的DTO并将您的类型映射到那个

最后一个很简单,但可能会增加工作量.

我很想先考虑第三个选项,因为第一个选项涉及重建提供者;第四个选项也会绝对出现在我要测试的东西上.


我苦苦挣扎了3,因为DCS在反序列化期间返回了不同对象;我改用了protobuf-net,所以下面的版本显示将partial class添加到现有的[DataContract]类型中,从而使其可以与BinaryFormatter一起使用.实际上,我怀疑(有证据)这也将使其效率大大提高(比原始的[Serializable]):

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using ProtoBuf;

/* DBML generated */
namespace My.Object.Model
{
    [DataContract]
    public partial class MyType
    {
        [DataMember(Order = 1)]
        public int Id { get; set; }

        [DataMember(Order = 2)]
        public string Name { get; set; }
    }
}
/* Your extra class file */
namespace My.Object.Model
{
    // this adds **extra** code into the existing MyType
    [Serializable]   
    public partial class MyType : ISerializable {
        public MyType() {}
        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {
            Serializer.Serialize(info, this);
        }
        protected MyType(SerializationInfo info, StreamingContext context) {
            Serializer.Merge(info, this);
        }
    }
}
/* quick test via BinaryFormatter */
namespace My.App
{
    using My.Object.Model;
    static class Program
    {
        static void Main()
        {
            BinaryFormatter bf = new BinaryFormatter();
            MyType obj = new MyType { Id = 123, Name = "abc" }, clone;
            using (MemoryStream ms = new MemoryStream())
            {
                bf.Serialize(ms, obj);
                ms.Position = 0;
                clone = (MyType)bf.Deserialize(ms);
            }
            Console.WriteLine(clone.Id);
            Console.WriteLine(clone.Name);
        }
    }
}

I'm just start switching to memcached and currently on testing with memcached.

I'm having 2 object, I created an object and put [Serializable] on it (for instance, let call this Object1), the other object is created using Linq DBML (Object2)..

I tried to memcached List<Object1>, it work just fine, like charm, everything here is cache and loaded properly.

But then, i move on to the Linq object, now i try to add to memcached List<Object2> this does not work, it did not add to memcached at all. no key was added

I move on and change the Serialization Mode to Unidirectional, do the add again, still no hope.

Is there anyway to make this work?

Here is the simple test I just wrote, using MemcachedProvider from codeplex to demonstrate:

public ActionResult Test()
{
    var returnObj = DistCache.Get<List<Post>>("testKey");
    if (returnObj == null)
    {
        DataContext _db = new DataContext();
        returnObj = _db.Posts.ToList();
        DistCache.Add("testKey", returnObj, new TimeSpan(29, 0, 0, 0));
        _db.Dispose();
    }

    return Content(returnObj.First().TITLE);
}

this is from Memcached, no STORE was called:

> NOT FOUND _x_testKey
>532 END
<528 get _x_testKey
> NOT FOUND _x_testKey
>528 END
<516 get _x_testKey
> NOT FOUND _x_testKey
>516 END

And in my SQL profiler, it called 3 query for 3 test time => Proved that the object called back from Memcached is null, then it query.

解决方案

It looks like the default implementation (DefaultTranscoder) is to use BinaryFormatter; the "unidirectional" stuff is an instruction to a different serializer (DataContractSerializer), and doesn't add [Serializable].

(Note: I've added a memo to myself to try to write a protobuf-net transcoder for memcached; that would be cool and would fix most of this for free)

I haven't tested, but a few options present themselves:

  1. write a different transcoder implementation that detects [DataContract] and uses DataContractSerializer, and hook this transcoder
  2. add [Serializable] to your types via a partial class (I'm not convinced this will work due to the LINQ field types not being serializable)
  3. add an ISerializable implementation in a partial class that uses DataContractSerializer
  4. like 3, but using protobuf-net, which a: works with "unidirectional", and b: is faster and smaller than DataContractSerializer
  5. write a serializable DTO and map your types to that

The last is simple but may add more work.

I'd be tempted to to look at the 3rd option first, as the 1st involves rebuilding the provider; the 4th option would also definitely be on my list of things to test.


I struggled with 3, due to the DCS returning a different object during deserialization; I switched to protobuf-net instead, so here's a version that shows adding a partial class to your existing [DataContract] type that makes it work with BinaryFormatter. Actually, I suspect (with evidence) this will also make it much efficient (than raw [Serializable]), too:

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using ProtoBuf;

/* DBML generated */
namespace My.Object.Model
{
    [DataContract]
    public partial class MyType
    {
        [DataMember(Order = 1)]
        public int Id { get; set; }

        [DataMember(Order = 2)]
        public string Name { get; set; }
    }
}
/* Your extra class file */
namespace My.Object.Model
{
    // this adds **extra** code into the existing MyType
    [Serializable]   
    public partial class MyType : ISerializable {
        public MyType() {}
        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {
            Serializer.Serialize(info, this);
        }
        protected MyType(SerializationInfo info, StreamingContext context) {
            Serializer.Merge(info, this);
        }
    }
}
/* quick test via BinaryFormatter */
namespace My.App
{
    using My.Object.Model;
    static class Program
    {
        static void Main()
        {
            BinaryFormatter bf = new BinaryFormatter();
            MyType obj = new MyType { Id = 123, Name = "abc" }, clone;
            using (MemoryStream ms = new MemoryStream())
            {
                bf.Serialize(ms, obj);
                ms.Position = 0;
                clone = (MyType)bf.Deserialize(ms);
            }
            Console.WriteLine(clone.Id);
            Console.WriteLine(clone.Name);
        }
    }
}

这篇关于无论如何,要为Memcached序列化linq对象吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆