【问题标题】:Fetching full object and it's child collections with derived types获取完整对象及其具有派生类型的子集合
【发布时间】:2016-04-11 18:07:09
【问题描述】:

我在使用 C# ORM 库中常见的惰性、急切和显式加载设计模式时遇到了问题,特别是对于具有自己集合的派生类型。

例如,我想持久化下面的模型:

public abstract class Offer
{
    public int Id { get; set; }
}

public class DiscountOffer : Offer
{
    public float Percent { get; set; }
}

public class ColourOffer : Offer
{
    public List<string> Colours { get; set; }
}

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; } = "Unknown";
    public IList<Offer> Offers { get; set; } = new List<Offer>();
}

我可以使用 Entity Framework 或 NHibernate 轻松地将其映射并保存到数据库,当我想从数据库中检索完整产品并使用 WCF 通过网络发送时,问题就出现了。

如果我有以下产品:

new Product
{
    Name = "Chair",
    Offers = new List<Offer>
    {
        new DiscountOffer { Percent = 0.2f },
        new ColourOffer
        {
            Colours = new List<string>
            {
                "Red", "Blue", "Green"
            }
        },
    }
};

如果产品是延迟加载的,则将其封装在代理中,以便知道何时获取子集合。这会带来一个问题,因为类型不符合预期,序列化将失败。

我找到了这个问题的几个答案:

  1. 禁用延迟加载和急切/显式加载。这一直有效,直到您遇到抽象集合。我可以找到Include/FetchColourOffer.Colours 路径的方法:

NHibernate:

session.Get<Product>(1).Fetch(p => p.Offers) // If ColourOffer Fetch Colours?

EF:

DbSet<Product> Products { get; set; }

// ...

Products.Include(p => p.Offers) // If ColourOffer Include Colours?
  1. 使用 DTO 和 AutoMapper。我已经收集到这通常是一个好主意,但我遇到了 AutoMapper 的相同问题,不知道如何处理代理类,因此我必须禁用延迟加载,这让我回到第 1 点。

  2. 使用IDataContractSurrogate 在序列化时加载内容。我尝试了一些在网络上流传的实现,但我无法得到任何工作。我相信这是因为会话在序列化点被关闭,因此无法获取集合的数据。

我现在不知道该怎么办。我只想加载一个完整的产品,但我找不到解决方案,这让我发疯了。

【问题讨论】:

  • 你真的试过Include()吗?你有什么问题吗?
  • 恐怕这是不可能的。要使其工作,您必须将所需的所有属性放在单个类中,并根据手动分配的鉴别器将其映射到 Dtos/Domain 对象。
  • 可能最好的选择是解决方案2,问题的解决方案很少见stackoverflow.com/questions/11816732/…

标签: c# entity-framework wcf nhibernate orm


【解决方案1】:

使用 Fluent NHibernate,添加 DefaultLazy.Never() 约定似乎会导致在请求时获取完整的对象图。

Fluently.Configure()
    // ...
    .Mappings(m => m
        .FluentMappings.AddFromAssemblyOf<MyClass>()
        .Conventions.Add(FluentNHibernate.Conventions.Helpers.DefaultLazy.Never()))
    // ...

这还有一个额外的好处,即我不必处理不使用 WCF 的代理。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-11
    • 2011-01-06
    • 1970-01-01
    • 1970-01-01
    • 2016-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多