Как запросить в LINQ & Entity Framework несопоставленное свойство - PullRequest
0 голосов
/ 13 июня 2018

Итак, я частично следовал из SO ответа о том, как сохранить свойство с типом данных массива в Entity Framework.В этом ответе я не следил за тем, чтобы строка InternalData была закрытой, а не общедоступной, поскольку я нахожу ее запахом кода, если она установлена ​​на общедоступную (пока не хватает репутации, чтобы комментировать).

Iтакже удалось сопоставить частную собственность в рамках сущности из этого блога .

Когда я выполняю CR (создание, чтение) из этой сущности, все идет хорошо.Однако, когда в моем запросе LINQ есть предложение where, использующее это свойство с типом данных массива, оно говорит, что "System.NotSupportedException: 'Указанный элемент типа не поддерживается в LINQ to Entities. Только инициализаторы, элементы сущностей и навигация сущностейсвойства поддерживаются. '".

Как обойти это?Вот соответствующие блоки кода:

public class ReminderSettings
{
   [Key]
   public string UserID { get; set; }
   [Column("RemindForPaymentStatus")]
   private string _remindForPaymentStatusCSV { get; set; }
   private Status[] _remindForPaymentStatus;
   [NotMapped]
   public Status[] RemindForPaymentStatus
   {
      get 
      {
         return Array.ConvertAll(_remindForPaymentStatusCSV.Split(','), e => (Status)Enum.Parse(typeof(Status), e));
      }
      set
      {
         _remindForPaymentStatus = value;
         _remindForPaymentStatusCSV = String.Join(",", _remindForPaymentStatus.Select(x => x.ToString()).ToArray());
      }
   }
   public static readonly Expression<Func<ReminderSettings, string>> RemindForPaymentStatusExpression = p => p._remindForPaymentStatusCSV;
}

public enum Status
{
  NotPaid = 0,
  PartiallyPaid = 1,
  FullyPaid = 2,
  Overpaid = 3 
}

protected override void OnModelCreating(DbModelBuuilder modelBuilder)
{
   modelBuilder.Entity<ReminderSettings>().Property(ReminderSettings.RemindForPaymentStatusExpression);
}

//This query will cause the error
public IEnumerable<ReminderSettings> GetReminderSettingsByPaymentStatus(Status[] statusArray)
{
   var query = ApplicationDbContext.ReminderSettings.Where(x => x.RemindForPaymentStatus.Intersect(statusArray).Any());
   return query.ToList(); //System.NotSupportedException: 'The specified type member 'RemindForPaymentStatus' is not supported in LINQ to Entities. Only initializers, entity members, and entity navigation properties are supported.'
}

1 Ответ

0 голосов
/ 13 июня 2018

Entity Framework не может переводить выражения LINQ в SQL, если они обращаются к свойству, аннотированному как [NotMapped].(Он также не может быть переведен, если свойство содержит собственный код C # в своем методе получения / установки).

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

// execute query on DB server and fetch items into memory
var reminders = dbContext.ReminderSettings.ToList(); 

// now that we work in-memory, LINQ does not need to translate our custom code to SQL anymore
var filtered = reminders.Where(r => r.RemindForPaymentStatus.Contains(Status.NotPaid)); 

Если это вызывает проблемы с производительностью, необходимо сделать поле поддержки вашего свойства NotMapped общедоступным и работать непосредственно с ним.

var filtered = dbContext.ReminderSettings
    .Where(r => r._remindForPaymentStatusCSV.Contains(Status.NotPaid.ToString("D"));

Редактировать Чтобы обрабатывать несколько Статусов в качестве параметров запроса, вы можете присоединять предложения Where в цикле (который ведет себя как AND).Это работает до тех пор, пока ваши значения перечисления Status различимы (т.е. нет статуса «11», если есть и статус «1»).

var query = dbContext.ReminderSettings.Select(r => r);
foreach(var statusParam in queryParams.Status) {
    var statusString = statusParam.ToString("D");
    query = query.Where(r => r._remindForPaymentStatusCSV.Contains(statusString));
}
var result = query.ToArray();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...