LINQ to SQL 对象的深度序列化

发布于 2024-10-21 23:21:45 字数 647 浏览 0 评论 0原文

我正在尝试序列化一些 LINQ to SQL 生成的对象,以便在可能的情况下与 Memcached 一起使用。我正在开发一个新的转码器,它将充当与 LINQ to SQL 对象一起使用的新序列化器。

似乎 DataContractSerializer 类不会尝试序列化关系实体。例如,如果我有以下关系:

Course -> CourseProject -> Project

Course 的属性将被序列化,但 CourseProjectProject 的关系列表将为空,而不是空。我很确定这是“单向”序列化的功能,以避免循环冗余。

这是问题所在......从缓存加载项目时,关系完全为空(空 IEnumerable,而不是 null),并且永远不会从数据库加载,如果要求。实际上,从缓存检索时课程的所有项目都会丢失。

如果我可以序列化比基础对象更深一两层的序列,那将会很有帮助。如果这是不可能的,那么我什至更喜欢从数据库延迟加载未序列化的数据,尽管这违背了序列化和缓存的目的。

I'm trying to serialize some LINQ to SQL generated objects to use with Memcached if at all possible. I am working on a new transcoder that will act as a new serializer to use with LINQ to SQL objects.

It seems like the DataContractSerializer classes do not event attempt to serialize relational entities. For example, if I had this relationship:

Course -> CourseProject -> Project

The properties for Course would be serialized, but the relational lists for CourseProject and Project would be empty, rather than null. I'm pretty sure this is a function of "Unidirectional" serializing to avoid cyclic redundancies.

Here is the problem with this... when loading items from cache the relationships are totally empty (empty IEnumerable, not null), and will never be loaded from the database if requested. Effectively, all projects for a course are lost when retrieving from cache.

If I could serialize even one or two levels deeper than just the base object it would be helpful. If that's not possible, then I would even prefer that unserialized data was lazy loaded from the database instead, though that sort of defeats the purpose of serializing and caching.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

戒ㄋ 2024-10-28 23:21:45

我通过创建一个通用包装器来处理这个问题,我用它来延迟加载关联:

 public class SqlRecord<T>{
     where T: ISqlDataObject

     public TAssociationRecord GetOneToOneAssociation<TAssociationRecord>(Expression<Func<T,TAssociationRecord>>> getAssociationPropertyExpression)
          where TAssociationRecord : ISqlDataObject
     {
     } 

     public IEnumerable<TAssociationRecord> GetOneToManyAssociation(Expression<Func<T,EntitySet<TAssociationRecord>>> getAssociationPropertyExpression)
         where TAssociationRecord: ISqlDataObject
     {
     }

 }

然后我向 LINQ to SQL 自动生成的所有数据对象添加了一个标记接口:

  public interface ISqlDataObject {}

我打赌您可以做类似的事情来满足您的需求。

I handled this problem by creating a generic wrapper which I used to lazy-load associations:

 public class SqlRecord<T>{
     where T: ISqlDataObject

     public TAssociationRecord GetOneToOneAssociation<TAssociationRecord>(Expression<Func<T,TAssociationRecord>>> getAssociationPropertyExpression)
          where TAssociationRecord : ISqlDataObject
     {
     } 

     public IEnumerable<TAssociationRecord> GetOneToManyAssociation(Expression<Func<T,EntitySet<TAssociationRecord>>> getAssociationPropertyExpression)
         where TAssociationRecord: ISqlDataObject
     {
     }

 }

Then I added a marker interface to all of the data objects that were automatically generated by LINQ to SQL:

  public interface ISqlDataObject {}

I bet you could do something similar to meet your needs.

傲娇萝莉攻 2024-10-28 23:21:45

好吧,经过几天的头撞桌子之后,我想我已经把这个问题弄清楚到了一个可行的水平...有几件事我确实必须首先掌握:

  1. LINQ to SQL 做了很多它的关系通过延迟加载进行构建。东西是按需加载的。
  2. 有两个实体上下文:附加分离。在分离状态下,不会跟踪对象更改,并且不会延迟加载关系(因为没有链接到实体的数据源)。
  3. 反序列化对象始终分离,因此不会有相关属性。

因此,真正的技巧是确保在反序列化对象后立即附加它们。这是我们系统中的一个真实示例(我们的系统有一些 memcached 包装器)。

string cacheKey = "apSpace_GetActiveSpacesForPerson_PersonID:" + personid;
List<apSpace> list = MemCached.Get<List<apSpace>>(cacheKey);
if (list == null)
{
    //Some complex, intensive query...
    list = (from s in BaseDB.apSpaces
            from so in BaseDB.apSpaceOwners
            from sp in BaseDB.apSpacePersons
            where (so.PersonID == personid
            && so.SpaceID == s.SpaceID
            && s.Deleted == false
            && s.IsArchived == false)
            || (sp.PersonID == personid
            && sp.SpaceID == s.SpaceID
            && s.Deleted == false
            && s.IsArchived == false)
            select s).Distinct().OrderBy(s => s.Name).ToList();
    //Cache the query result
    MemCached.Store(cacheKey, list);
}
else
    BaseDB.apSpaces.AttachAll(list); //Attach immediately!

return list;

显然,就缓存相关数据而言,这不是灵丹妙药,但它确实允许您保留关系,同时缓存密集查询的初始结果。无论如何,LINQ to SQL 都会延迟加载此后的所有内容。

Alright, after several days of banging my head on my desk I think I have this figured out to a workable level... there was a few things I really had to get a grasp on first:

  1. LINQ to SQL does a lot of its relationship building through lazy loading. Things are loaded on demand.
  2. There are two entity contexts: Attached and Detached. In the detached state, object changes are not tracked, and relationships are not lazy loaded (as there is no data source linked to the entity).
  3. Deserialized objects are always detached, thus will have no related properties.

So the real trick is to just make sure that you attach the object(s) as soon as you deserialize them. Here is a real world example from our system (we have some memcached wrappers in place for our system).

string cacheKey = "apSpace_GetActiveSpacesForPerson_PersonID:" + personid;
List<apSpace> list = MemCached.Get<List<apSpace>>(cacheKey);
if (list == null)
{
    //Some complex, intensive query...
    list = (from s in BaseDB.apSpaces
            from so in BaseDB.apSpaceOwners
            from sp in BaseDB.apSpacePersons
            where (so.PersonID == personid
            && so.SpaceID == s.SpaceID
            && s.Deleted == false
            && s.IsArchived == false)
            || (sp.PersonID == personid
            && sp.SpaceID == s.SpaceID
            && s.Deleted == false
            && s.IsArchived == false)
            select s).Distinct().OrderBy(s => s.Name).ToList();
    //Cache the query result
    MemCached.Store(cacheKey, list);
}
else
    BaseDB.apSpaces.AttachAll(list); //Attach immediately!

return list;

Obviously this is not a silver bullet as far as caching related data, but it does allow you to preserve relationships and at the same time cache the initial result of intensive query. LINQ to SQL would be lazy-loading everything after that regardless.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文