[英]EF6 using custom property in a linq query
我有一个具有以下属性的类:
[NotMapped]
public string Key
{
get
{
return string.Format("{0}_{1}", Process.Name, LocalSequenceNumber);
}
}
本地序列号是由缓存支持的并发字典形式的计算整数。
我希望在LINQ查询中使用上面的Key属性,但会出现异常:
LINQ to Entities不支持指定的类型成员'Key'。 仅支持初始化程序,实体成员和实体导航属性。
我知道为什么会收到此错误,但是我不太确定如何解决该错误。 当前,Key属性为我不想提供的类提供了很好的封装。 在库方面有任何建议,或在此方面使用简单的模式?
编辑:这是引发异常的查询:
db.Cars.SingleOrDefault(c => c.Id == id && c.Key == key);
DelegateDecompiler软件包https://github.com/hazzik/DelegateDecompiler可以处理这种情况。
使用Computed
属性装饰属性,然后在添加Decompile
方法的情况下进行如下查询:
db.Cars.Decompile().SingleOrDefault(c => c.Id == id && c.Key == key)
有许多第三方程序包可以解决此问题。 我也相信EF.Core中有一些方法可以提供帮助,但是,我将建议2个“纯实体框架6”解决方案。
db.Cars.Where(c => c.Id == id).ToList().SingleOrDefault(c => c.Key == key)
这仍将您的逻辑封装在类中,但是您没有从SQL执行中受益。
本质上,您将创建一个表示数据传输对象的EF POCO的“视图”。 它具有视图所需的属性,并确定如何将数据从数据库投影到视图。
// Poco:
public class Car {
public int Id {get;set;}
public string LocalSequenceNumber {get;set;}
public int ProcessId {get;set; }
public virtual Process Process {get;set;}
// ...
}
public class Process {
// ...
}
// View+Projector:
public class CarView
{
public int Id {get;set;}
public string Color {get;set;}
public string Key {get;set;}
public static Expression<Func<Car, CarView>> Projector = car => new CarView {
Id = car.Id,
Color = car.Color,
Key = car.Process.Name + " " + car.LocalSequenceNumber
}
}
// calling code
var car = db.Cars.Select(CarView.Project).SingleOrDefault(cv => cv.Id == id && cv.Key == key)
这将评估数据库中的所有代码,同时将您的业务逻辑封装在代码中。
LocalSequenceNumber
您忘了告诉我们什么是Process.Name
和LocalSequenceNumber
。 从标识符看来,它们不是您Cars
一部分,而是本地流程中的值。 为什么不在查询之前计算密钥?
var key = string.Format("{0}_{1}", Process.Name, LocalSequenceNumber);
db.Cars.SingleOrDefault(c => c.Id == id && c.Key == key);
如果,另一方面, Process.Name
或LocalSequenceNumber
是Car
性能,你必须改变IQueryable.Expression
只使用性能,并且可以通过你的翻译方法就是在你的LINQ查询IQueryable.Provider
到SQL。
幸运的是,您的Provider
知道ToSTring()
和字符串串联的概念,因此您可以使用它
当您在Queryable.Where
中使用属性Key
时,建议使用功能WhereKey
扩展IQueryable
。 如果扩展功能对您来说有点神奇,请参阅扩展方法揭秘
public static IQueryable<Car> WhereKey(this IQueryable<Car> cars, int id, string key)
{
return cars.Where(car => car.Id == id
&& key == car.Process.Name.ToString() + "_" + car.LocalSequenceNumber.ToString());
}
用法:
int carId = ...
string carKey = ...
var result = myDbContext.Cars
.WhereKey(carId, carKey)
.FirstOrDefault();
考虑创建只检查密钥的WhereKey
。 与在Id
上选择的Where
串联。
var result = myDbContext.Cars
.Where(car => car.Id == id)
.WhereKey(carKey)
.FirstOrDefault();
如果Process.Name
或LocalSequenceNumber
不是Car的一部分,请将其添加为参数。 你明白了。
考虑创建只检查密钥的WhereKey
。 与在Id
上选择的Where
串联。
如果需要,可以创建WhereKeyFirstOrDefault()
,但是我怀疑这是否有用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.