构建 Linq2Sql 查询时如何将对象的属性(而不是对象)传递到表达式中?



tl;dr:我正在寻找一种方法,在构建Linq2Sql查询时,将对象的属性image.Member(而不是对象image)传递到表达式中。通过这种方式,我将使用Expression<Func<Member, bool>>而不是Expression<Func<Image, bool>>


这是我的域模型(如果重要的话,EF 5):

class Image
{
public string Url { get; set;}
public Member Member { get; set;}   // user who uploaded the image
}
class Member
{
public int Id { get; set;}
public bool IsPrivate { get; set;}
public string AboutMe { get; set;}  
public string ScreenName { get; set;}   
[NotMapped]
public bool IsSearchable
{
get
{
return IsPrivate == false && 
string.IsNullOrEmpty(AboutMe) == false &&
string.IsNullOrEmpty(ScreenName) == false;
}
}
}

接下来,我想用以下逻辑从数据库中获取所有图像:

如果用户已登录,请拍摄all his images和所有其他图像是CCD_ 6的成员。如果用户未登录,只需是CCD_ 7的所有其他成员的所有图像。

在Linq2对象中,这看起来像这样:

var images = imagesRepository.All().ToList().AsIEnumerable();
if (this.User == null)
{
images = images.Where(x => x.Member.IsSearchable == true);
}
else
{
var currentMemberId = this.User.Id;
images = images.Where(x => x.Member.IsSearchable == true || x.Member.Id == currentMemberId);
}

当然,这是低效的——我不想从DB加载10000个图像,只为了得到其中的10个。这就引出了Linq2Sql注意:我知道我可以将逻辑从"IsSearchable"复制到"Where"子句中,我会得到正确的"IQueryable",但我有两个问题:

  1. IsSearchable逻辑以后很容易更改,而且我永远不会记得这个复制/粘贴
  2. 我将不得不复制它两次(因为currentMemberId处于OR条件下)——这将使代码难以阅读

这让我相信我唯一的解决方案就是使用Expression。我们开始了(感谢这个表达式或问题):

var parameterExpression = Expression.Parameter(typeof(Image));
Expression<Func<Image, bool>> memberIsSearchable = 
i => i.Member.IsPrivate == false && 
string.IsNullOrEmpty(i.Member.AboutMe) == false && 
string.IsNullOrEmpty(i.Member.ScreenName) == false;  
Expression<Func<Image, bool>> memberById = 
i => i.Member.MemberId == currentMemberId;
var combined = Expression.Lambda<Func<Image, bool>>(
Expression.Or(
Expression.Invoke(memberIsSearchable, parameterExpression),
Expression.Invoke(memberById, parameterExpression)), 
parameterExpression);
var images = imagesRepository.All();
if (this.User == null)
{
images = images.Where(memberIsSearchable);
}
else
{
images = images.Where(combined);
}

这可以很好地转换为SQL。

问题来了:

有可能在表达式定义中去掉Image类型吗

Expression<Func<Image, bool>> memberIsSearchable = ...

并将其替换为Member,并以某种方式告诉表达式在创建查询时使用"Image"对象中的"Member":

Expression<Func<Member, bool>> memberIsSearchable = 
m => m.IsPrivate == false && 
string.IsNullOrEmpty(m.AboutMe) == false && 
string.IsNullOrEmpty(m.ScreenName) == false;
images = images.Where(x => memberIsSearchable(x.Member));  // pseudocode

这样做的原因是为了使memberIsSearchable表达式具有通用性,并在项目的其他部分中使用它。

我花了一段时间才弄清楚你的问题到底是什么——我想,我现在明白了。

尝试从成员开始(而不是从图像开始)。也许你需要引入额外的导航属性:

Expression<Func<Member, bool>> IsSearchable =  member => !member.IsPrivate
&& !String.IsNullOrEmpty(member.AboutMe)
&& !String.IsNullOrEmpty(member.ScreenName);
Member currentUser = null;
using (var container = new /**/())
{
var images = container.Members.Where(IsSearchable).SelectMany(member => member.Images);
if (currentUser != null)
images = images.Concat(currentUser.Images);
var result = images.ToArray();
}

相关内容

  • 没有找到相关文章

最新更新