【问题标题】:Can I lazy load part of an entity in Entity Framework 6 with Entity Splitting?我可以使用实体拆分在 Entity Framework 6 中延迟加载实体的一部分吗?
【发布时间】:2013-12-06 11:52:01
【问题描述】:

我是 Entity Framework 的新手,虽然它比 NHibernate 有很多优点,但我很失望地发现它不支持延迟加载属性。

参加这门课:

public class Product
{ 
    public virtual Guid Id {get;set;}
    public virtual string Name {get;set;}
    public virtual string Details {get;set;}
}

我的计划是使用实体拆分将其映射到两个表:

CREATE TABLE [dbo].[Product](
[Id] [uniqueidentifier] NOT NULL PRIMARY KEY,
[Name] [nvarchar](50) NULL
) 

CREATE TABLE [dbo].[ProductDetails](
[Id] [uniqueidentifier] NOT NULL PRIMARY KEY,
[Details] [nvarchar](max) NULL
)

这是我的流畅映射:

modelBuilder.Entity<Product>()
            .Map(m =>
            {
                m.Properties(t => new { t.Id, t.Name });
                m.ToTable("Product");
            })
            .Map(m =>
            {
                m.Properties(t => new { t.Id, t.Details});
                m.ToTable("ProductDetails");
            });

我希望能够在不加载详细信息字段的情况下显示产品列表。但是,每当我加载产品时,它总是会进行 INNER JOIN。我希望它只从 Product 中读取,然后在我读取 Details 属性时从 ProductDetails 中读取。

如何做到这一点?

如果不可能,我还能如何实现属性的延迟加载?

表拆分是不可接受的,因为这意味着持久性机制决定了域的设计。

在 CodeCaster 回答后编辑:

域是固定的 - 我不想要引入 ProductDetails 实体的解决方案。这个问题是关于持久化现有的域模型。更改域并不能回答问题。

【问题讨论】:

    标签: c# sql entity-framework lazy-loading domain-model


    【解决方案1】:

    如何实现【从拆分表延迟加载标量属性】?

    如果不可能,我还能如何实现属性的延迟加载?

    can't,延迟加载仅适用于navigation properties

    如果您像这样更改模型:

    public class Product
    { 
        public virtual Guid Id {get;set;}
        public virtual string Name {get;set;}
    
        public virtual ProductDetails Details {get;set;}
    }
    
    public class ProductDetails
    { 
        public virtual Guid Product_Id {get;set;}
        public virtual string Details {get;set;}
    }
    

    您可以使用延迟加载,其中只有在您获得Product.Details 属性时才会查询ProductDetails

    [是否]这意味着持久性机制决定了域的设计?

    实体模型不一定是领域模型。

    【讨论】:

    • 也许我不清楚,但这正是我试图避免的。你说实体模型不一定是域模型。我开始认为这意味着 EF 不适合不了解持久性的域模型?
    • “EF 不适合对持久性无知的域模型?” - EF 是一种与 SQL 数据库密切相关的 ORM,很难被认为对持久性无知. :)
    • 一个设计良好的域甚至不知道 O/RM,甚至不知道 O/RM 的存在。我通常可以在我的系统中换掉 NHibernate 或 EF,甚至可以换掉一个文档数据库(虽然我还没有尝试过)。
    • 您展示的Product 很可能是一个域模型,但是如果您想使用实体框架中描述的延迟加载,则必须使用我上面显示的结构;那是你的实体模型。当然,您的领域模型不应该知道您的实体模型,甚至不应该受到影响,但是为了让您的Product 领域模型保存在我的ProductProductDetails 实体模型中,您需要一个数据访问/映射层之间。 “延迟加载”绝对不是域模型的属性或任务。
    • 谢谢。我赞成这个答案,因为它很有帮助,但正确的答案只是“不”。如果你很快得到另一个答案,只是说我会接受它!
    【解决方案2】:

    您可以使用我在项目中使用的以下类:

    /// <summary>
    /// Wrapper class for an unlimited size string property 
    /// to allow for lazy loading with Entity Framework.
    /// </summary>
    public class Text
    {
        [MaxLength]
        public string Value { get; set; }
    
        public static implicit operator string(Text val)
        {
            return val.Value;
        }
    
        public static implicit operator Text(string val)
        {
            return new Text { Value = val };
        }
    
        public override string ToString()
        {
            return Value;
        }
    }
    

    由于该类覆盖了隐式运算符,因此您可以将 Text 类型的对象视为普通字符串:

    Text myText = "Hello Text";
    

    在您的实体类中,您可以简单地创建一个虚拟(延迟加载)属性:

    public virtual Text Comment { get; set; }
    

    【讨论】:

      【解决方案3】:

      您可以使用匿名类型仅加载实体的一部分,但不能将部分实体加载到同一个实体类中。 (或者,你可以“手动”。)

      var products =
         context
         .Products
         .Select(p => new {
            p.ID,
            p.Name
         }).AsEnumerable() // come out of EF
         .Select(anon => new Product { // manually load into product objects
            ID = anon.ID,
            Name = anon.Name
         }).ToList();
      

      也可以只使用匿名类型或其他类型。

      不过,您还必须稍后“手动”加载 Details 属性。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-12-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-01
        • 1970-01-01
        • 2020-10-31
        相关资源
        最近更新 更多