Entity framework EF6延迟加载:添加时加载整个集合?

Entity framework EF6延迟加载:添加时加载整个集合?,entity-framework,entity-framework-6,Entity Framework,Entity Framework 6,我的实体上有以下集合导航属性: public virtual ICollection<OrderIntegrationLogEntry> LogEntries { get; set; } 似乎这一行代码: integration.LogEntries.Add(new OrderIntegrationLogEntry { Id = Guid.NewGuid(), CreatedUtc = DateTime.UtcNow, Message = message,

我的实体上有以下集合导航属性:

public virtual ICollection<OrderIntegrationLogEntry> LogEntries { get; set; }
似乎这一行代码:

integration.LogEntries.Add(new OrderIntegrationLogEntry
{
    Id = Guid.NewGuid(),
    CreatedUtc = DateTime.UtcNow,
    Message = message,
    Level = level,
    Detail = detail
});
…生成一个加载集合内容的查询:

SELECT [Extent1].[Id] AS [Id], [Extent1].[IntegrationId] AS [IntegrationId],
[Extent1].[CreatedUtc] AS [CreatedUtc], [Extent1].[Level] AS [Level],
[Extent1].[Message] AS [Message], [Extent1].[Detail] AS [Detail]
FROM [dbo].[OrderIntegrationLogEntries] AS [Extent1]
WHERE [Extent1].[IntegrationId] = @EntityKeyValue1

我没想到会这样:它不应该只是阶段性的添加吗?是否需要以其他方式进行配置?

为了启用延迟加载,EF将创建从模型派生的代理类。在这些类中,它重写导航属性以实现延迟加载。这就是为什么应该定义导航属性
virtual
,以便EF可以覆盖它们。
调用
integration.LogEntries.Add
时,将调用
LogEntries
属性的getter,该getter将触发延迟加载操作

您可以使用以下代码暂时禁用延迟加载:

context.Configuration.LazyLoadingEnabled = false;

正如Ivan所指出的,您将LogEntries称为getter,这会导致延迟加载

如果不想关闭延迟加载,则只需设置新entitiy的IntegrationId和SaveChanges(),而不是将日志实体添加到父项的导航属性。乙二醇

此外,如果这是SQL Server(可能还有其他平台),请使用顺序GUID生成。插入带有随机guid的行作为其前导键列是不必要的昂贵。对于SQL Server,您可以在数据库中使用NEWSEQUENTIALID()函数作为默认值生成顺序GUID,也可以在客户机上生成顺序GUID

  public class SQLGuidUtil
  {
      [DllImport("rpcrt4.dll", SetLastError = true)]
      static extern int UuidCreateSequential(out Guid guid);

      public static Guid NewSequentialId()
      {
        Guid guid;
        UuidCreateSequential(out guid);
        var s = guid.ToByteArray();
        var t = new byte[16];
        t[3] = s[0];
        t[2] = s[1];
        t[1] = s[2];
        t[0] = s[3];
        t[5] = s[4];
        t[4] = s[5];
        t[7] = s[6];
        t[6] = s[7];
        t[8] = s[8];
        t[9] = s[9];
        t[10] = s[10];
        t[11] = s[11];
        t[12] = s[12];
        t[13] = s[13];
        t[14] = s[14];
        t[15] = s[15];
        return new Guid(t);
      }
  }

<> P>如果你希望日志条目以集成为基础进行访问,你也应该考虑翻转键列的顺序。将集成的日志条目存储在一起。乙二醇

this.HasKey(i => new {i.IntegrationId, i.Id});
如果您不在Windows上,您可以通过从随机GUID开始并递增4个低位字节来滚动自己的顺序GUID生成器。guid只在AppDomain中是连续的,但这并不重要

大概是这样的:

namespace NewSequentialId
{
    public class SQLGuidUtil
    {
        static object synclock = new object();
        static uint seq = 0;
        static byte[] seed = Guid.NewGuid().ToByteArray();
        public static Guid NewSequentialId()
        {
            uint nextVal;
            byte[] buf;

            lock (synclock)
            {
                nextVal = seq++;
                buf = (byte[])seed.Clone();

                if (nextVal == 0xFFFFFFFF)
                {
                    seed = Guid.NewGuid().ToByteArray();
                    seq = 0;
                }
            }

            var seqbytes = BitConverter.GetBytes(nextVal);

            if (BitConverter.IsLittleEndian)
            {
                buf[0] = seqbytes[3];
                buf[1] = seqbytes[2];
                buf[2] = seqbytes[1];
                buf[3] = seqbytes[0];
            }
            else
            {
                buf[0] = seqbytes[0];
                buf[1] = seqbytes[1];
                buf[2] = seqbytes[2];
                buf[3] = seqbytes[3];
            }

            return new Guid(buf);
        }
    }
}

嗯,我真的想要懒加载。我只是不想在添加时使用它?我想不出任何解决方法,因为它都是在幕后完成的,不会让程序员改变行为。您不能仅为此上下文的实例关闭延迟加载吗?延迟加载由属性getter触发。和
integration.LogEntries.Add(…)
包括属性getter
integration.LogEntries
。如果不希望发生延迟加载,请在添加过程中禁用它,不要跟踪该项或将导航属性项附加到集合,而是将其导航属性/FK设置为正确的值。谢谢-我使用延迟加载有效地从使用父实体的类中隐藏对上下文的依赖关系。看来,为了解决这个问题,我必须以某种方式公开它或添加功能。使用复合键的提示非常棒,谢谢。顺序GUID-您知道有一个.NET核心版本吗?同样引用MSDN的话,“你永远不应该使用这个UUID来识别一个对你的计算机来说不是严格本地的对象。”我正在寻找一个合适的策略——在这种情况下,我们应该使用常规的int-identity。你可以从.NET核心使用客户端顺序GUID生成,但只能在Windows上使用。SQL Server有一个UUIDCreateSequential的Linux实现,但恐怕没有其他实现。MSDN上针对顺序GUID的警告适用于没有唯一MAC地址的计算机。即使这样,也不太可能生成重复的值。我想知道“自产”解决方案有多危险:对于每个进程,创建一个新的完全随机的GUID,可能将最后几个字节归零,然后从那里递增。每个进程都有自己的顺序范围,这看起来类似于UuidCreateSequential解决方案?这是个好主意。这种模式有时被称为“组合guid”,您可以很容易地做到这一点。请参见编辑。
this.HasKey(i => new {i.IntegrationId, i.Id});
namespace NewSequentialId
{
    public class SQLGuidUtil
    {
        static object synclock = new object();
        static uint seq = 0;
        static byte[] seed = Guid.NewGuid().ToByteArray();
        public static Guid NewSequentialId()
        {
            uint nextVal;
            byte[] buf;

            lock (synclock)
            {
                nextVal = seq++;
                buf = (byte[])seed.Clone();

                if (nextVal == 0xFFFFFFFF)
                {
                    seed = Guid.NewGuid().ToByteArray();
                    seq = 0;
                }
            }

            var seqbytes = BitConverter.GetBytes(nextVal);

            if (BitConverter.IsLittleEndian)
            {
                buf[0] = seqbytes[3];
                buf[1] = seqbytes[2];
                buf[2] = seqbytes[1];
                buf[3] = seqbytes[0];
            }
            else
            {
                buf[0] = seqbytes[0];
                buf[1] = seqbytes[1];
                buf[2] = seqbytes[2];
                buf[3] = seqbytes[3];
            }

            return new Guid(buf);
        }
    }
}