NHibernate Criteria:如何排除某些映射属性/集合?

发布于 2024-11-25 19:15:44 字数 3243 浏览 4 评论 0原文

这是我的(简化的)模型: Ticket ->客户回调

我已经映射了我的票证,以便在加载时,回调也是如此。

        base.HasMany<TechSupportCallback>(x => x.Callbacks)  
            .KeyColumn(Fields.TRACKED_ITEM_ID)
            .Not.LazyLoad()
            .Inverse()
            .Cache.ReadWrite();

这不是延迟加载,因为否则当 Web 服务尝试序列化(和加载)代理时,我将收到“没有会话来加载实体”。 (使用存储库来获取数据。)

它也是双向的..(在 CallbackMap 中)

        base.References(x => x.Ticket)
            .Column(Fields.TRACKED_ITEM_ID)
            .Not.Nullable();

现在..我们需要向代理显示他们的回调列表 - 只是他们的回调。 -- 当我使用回调条件进行查询时,我无法阻止加载票证(以及随后的整个图表,包括其他集合)。我之前曾尝试设置 FetchMode.Lazy,然后迭代每个结果回调并将 Ticket 设置为 null,但这似乎被忽略了。

             // open session & transaction in using (..)
                var query = session.CreateCriteria<TechSupportCallback>()
                    .SetCacheable(true)
                    .SetCacheRegion("CallbacksByUserAndGroups")
                    .SetFetchMode("Ticket", FetchMode.Lazy) // <-- but this doesn't work!
                    .SetMaxResults(AegisDataContext.Current.GetMaxRecordCount())
                    ;
                rValue = query.List<TechSupportCallback>();
                rvalue.ForEach(x => x.Ticket = null;); // <-- since this is already retrieved, doing this merely prevents it from going back across the wire
                tx.Commit();
             // usings end (..)

我应该用投影来做这件事吗? 问题是..我无法找到用于填充实体或实体列表的投影示例 - 仅用作子实体的子查询或类似的限制父实体列表。

我真的可以在这方面使用一些指导。


[编辑]

我尝试按照建议使用投影,但是:

我得到以下信息:(这是由于错误,所以我已经停止使用缓存并且它可以工作。http://nhibernate.jira.com/browse/NH-1090)

System.InvalidCastException occurred
  Message=Unable to cast object of type 'AEGISweb.Data.Entities.TechSupportCallback' to type 'System.Object[]'.
  Source=NHibernate
  StackTrace:
       at NHibernate.Cache.StandardQueryCache.Put(QueryKey key, ICacheAssembler[] returnTypes, IList result, Boolean isNaturalKeyLookup, ISessionImplementor session)
  InnerException: 

 rValue = query.List<TechSupportCallback>();

投影列表定义就像

 // only return the properties we want!
 .SetProjection(Projections.ProjectionList()
     .Add(Projections.Alias(Projections.Id(), ex.NameOf(x => x.ID))) // 
     .Add(Projections.Alias(Projections.Property(ex.NameOf(x => x.ContactID)), ex.NameOf(x => x.ContactID)))
     // ...
  )
  .SetResultTra...;
  rValue = query.List<TechSupportCallback>();

映射一样

    public TechSupportCallbackMap()
    {
        base.Cache.ReadWrite();
        base.Not.LazyLoad();

        base.Table("TS_CALLBACKS");

        base.Id(x => x.ID, Fields.ID)
            .GeneratedBy.Sequence("SEQ_TS_CALLBACKS");

        base.References(x => x.Ticket)
            .Column(Fields.TRACKED_ITEM_ID)
            .Not.Nullable();

        base.Map(x => x.TrackedItemID, Fields.TRACKED_ITEM_ID)
            .Not.Insert()
            .Not.Update()
            .Generated.Always()
            ;
        // ...
     }

Here's my (simplified) model: Ticket -> Customer Callback (s)

I have my Ticket mapped so that when it's loaded, the Callbacks are as well.

        base.HasMany<TechSupportCallback>(x => x.Callbacks)  
            .KeyColumn(Fields.TRACKED_ITEM_ID)
            .Not.LazyLoad()
            .Inverse()
            .Cache.ReadWrite();

This is not lazy loading because otherwise I'll get 'no session to load entities' when the web service tries to serialize (and load) the proxy. (Using repositories to fetch data.)

It's also bi-directional .. (in the CallbackMap)

        base.References(x => x.Ticket)
            .Column(Fields.TRACKED_ITEM_ID)
            .Not.Nullable();

Now .. we need to show an agent a list of their callbacks - JUST their callbacks.
-- When I query using Criteria for the Callbacks, I cannot prevent the Ticket (and subsequently it's entire graph, including other collections) from being loaded. I had previously tried to set FetchMode.Lazy, then iterate each resulting Callback and set Ticket to null, but that seems to be ignored.

             // open session & transaction in using (..)
                var query = session.CreateCriteria<TechSupportCallback>()
                    .SetCacheable(true)
                    .SetCacheRegion("CallbacksByUserAndGroups")
                    .SetFetchMode("Ticket", FetchMode.Lazy) // <-- but this doesn't work!
                    .SetMaxResults(AegisDataContext.Current.GetMaxRecordCount())
                    ;
                rValue = query.List<TechSupportCallback>();
                rvalue.ForEach(x => x.Ticket = null;); // <-- since this is already retrieved, doing this merely prevents it from going back across the wire
                tx.Commit();
             // usings end (..)

Should I be doing this with a projection instead?
The problem with that .. is I've not been able to find an example of projections being used to populate an entity, or a list of them -- only to be used as a subquery on a child entity or something similar to restrict a list of parent entities.

I could really use some guidance on this.


[EDIT]

I tried using a projection as suggested but:

I'm getting the following: (this was because of a bug, and so I've since stopped using the cache and it works. http://nhibernate.jira.com/browse/NH-1090)

System.InvalidCastException occurred
  Message=Unable to cast object of type 'AEGISweb.Data.Entities.TechSupportCallback' to type 'System.Object[]'.
  Source=NHibernate
  StackTrace:
       at NHibernate.Cache.StandardQueryCache.Put(QueryKey key, ICacheAssembler[] returnTypes, IList result, Boolean isNaturalKeyLookup, ISessionImplementor session)
  InnerException: 

at

 rValue = query.List<TechSupportCallback>();

with the projection list defined like

 // only return the properties we want!
 .SetProjection(Projections.ProjectionList()
     .Add(Projections.Alias(Projections.Id(), ex.NameOf(x => x.ID))) // 
     .Add(Projections.Alias(Projections.Property(ex.NameOf(x => x.ContactID)), ex.NameOf(x => x.ContactID)))
     // ...
  )
  .SetResultTra...;
  rValue = query.List<TechSupportCallback>();

mapped like

    public TechSupportCallbackMap()
    {
        base.Cache.ReadWrite();
        base.Not.LazyLoad();

        base.Table("TS_CALLBACKS");

        base.Id(x => x.ID, Fields.ID)
            .GeneratedBy.Sequence("SEQ_TS_CALLBACKS");

        base.References(x => x.Ticket)
            .Column(Fields.TRACKED_ITEM_ID)
            .Not.Nullable();

        base.Map(x => x.TrackedItemID, Fields.TRACKED_ITEM_ID)
            .Not.Insert()
            .Not.Update()
            .Generated.Always()
            ;
        // ...
     }

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

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

发布评论

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

评论(1

子栖 2024-12-02 19:15:44

这听起来像是一项专门用于预测的工作。

var query = session.CreateCriteria<TechSupportCallback>()
                    .SetCacheable(true)
                    .SetCacheRegion("CallbacksByUserAndGroups")
                    .SetFetchMode("Ticket", FetchMode.Lazy)
                    .SetMaxResults(AegisDataContext.Current.GetMaxRecordCount())
                    .SetProjection(Projections.ProjectionList().
                                         .Add(Projections.Alias(Projections.Id(), "Id")
                                         .Add(Projections.Alias(Projections.Property("Prop"), "Prop")))
                    .SetResultTransformer(Transformers.AliasToBean<TechSupportCallback>())
                    ;

只需列出您想要包含和排除 Ticket 实体的所有属性。您甚至可以创建一个 POCO 类来简单地封装此查询的结果。而不是使用现有的实体类。

This sounds like it's a job exactly for projections.

var query = session.CreateCriteria<TechSupportCallback>()
                    .SetCacheable(true)
                    .SetCacheRegion("CallbacksByUserAndGroups")
                    .SetFetchMode("Ticket", FetchMode.Lazy)
                    .SetMaxResults(AegisDataContext.Current.GetMaxRecordCount())
                    .SetProjection(Projections.ProjectionList().
                                         .Add(Projections.Alias(Projections.Id(), "Id")
                                         .Add(Projections.Alias(Projections.Property("Prop"), "Prop")))
                    .SetResultTransformer(Transformers.AliasToBean<TechSupportCallback>())
                    ;

Simply list all the properties you want to include and exclude the Ticket entity. You can even create a POCO class simply for encapsulating the results of this query. Rather than using an existing entity class.

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