EF6 отложенная загрузка: загружает всю коллекцию при добавлении? - PullRequest
0 голосов
/ 10 ноября 2018

У меня есть следующее свойство навигации коллекции для моей сущности:

public virtual ICollection<OrderIntegrationLogEntry> LogEntries { get; set; }

А сущность OrderIntegrationLogEntry имеет небольшую конфигурацию:

this.HasKey(i => new {i.Id, i.IntegrationId});
this.HasRequired(i => i.Integration).WithMany(i => i.LogEntries).HasForeignKey(i => i.IntegrationId).WillCascadeOnDelete(true);

Кажется, что эта строка кода:

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

Я не ожидал этого: не должно ли это просто добавить дополнение?Нужно ли настраивать другим способом?

Ответы [ 2 ]

0 голосов
/ 10 ноября 2018

Как отметил Иван, вы вызвали метод получения LogEntries, который вызывает отложенную загрузку.

Если вы не хотите отключать отложенную загрузку, тогда вместо добавления объекта журнала к свойству навигации родительского объекта просто установите IntegrationId для нового полномочий и SaveChanges (). например,

var entry = new OrderIntegrationLogEntry()
{
    Id = Guid.NewGuid(),
    IntegrationId = integration.Id,
    CreatedUtc = DateTime.UtcNow,
    Message = message,
    Level = level,
    Detail = detail
);
db.OrderIntegrationLogEntries.Add(entry);
db.SaveChanges();

Также, если это SQL Server (и, возможно, другие платформы), используйте последовательную генерацию GUID. Вставка строки со случайной направляющей в качестве ключевого столбца является излишне дорогой. Для SQL Server вы можете генерировать последовательные идентификаторы GUID в базе данных с функцией NEWSEQUENTIALID () по умолчанию или на клиенте

  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);
      }
  }

Как создать последовательные идентификаторы GUID для SQL Server в .NET

Вам также следует рассмотреть возможность изменения порядка ваших ключевых столбцов, если вы ожидаете, что записи журнала будут доступны в основном на основе интеграции по интеграции. Это будет хранить записи журнала для интеграции вместе. EG

this.HasKey(i => new {i.IntegrationId, i.Id});

Если вы не в Windows, вы можете запустить свой собственный последовательный генератор GUID, начав со случайного GUID и увеличивая 4 младших байта. Идентификаторы GUID будут последовательными только внутри домена приложения, но это не должно иметь большого значения.

Примерно так:

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);
        }
    }
}
0 голосов
/ 10 ноября 2018

Чтобы включить отложенную загрузку, EF создает прокси-классы, полученные из вашей модели. В этих классах он переопределяет свойства навигации для реализации отложенной загрузки. Вот почему ваши навигационные свойства должны быть определены virtual, чтобы EF мог их переопределить.
Когда вы вызываете integration.LogEntries.Add, вызывается метод получения вашего свойства LogEntries, который запускает операцию отложенной загрузки.

Вы можете временно отключить отложенную загрузку, используя следующий код:

context.Configuration.LazyLoadingEnabled = false;
...