所以我部分地从SO answer开始关于如何在Entity Framework中存储具有数组数据类型的属性。我没有回答的问题是将字符串InternalData设置为私有而不是公共,因为如果将其设置为公共(还没有足够的声誉在那里评论),我会发现代码气味。
我还设法在此实体框架中映射私有属性blog。
当我从该实体执行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.'
}
答案 0 :(得分:1)
如果实体框架访问注释为[NotMapped]
的属性,则它无法将LINQ表达式转换为SQL。 (如果属性在其getter / setter中包含自定义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)。只要您的状态枚举值可以区分(即如果状态为“1”,则没有状态“11”),则此方法有效。
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();