梦想成为现实:在Enitity Framework中以理想方式实现指定字段查询

本文解决了Entity Framework中LINQ查询指定返回字段的问题。通过调整DbSet中的实体类型与查询构造的新类型之间的关系,实现了理想的查询效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在之前的随笔“博客园现代化建设—[Entity Framework]在LINQ查询中指定返回的字段”中,我们找到了问题的原因,却没有找到解决方法。

而对于理想中的解决方法,我们依然恋恋不忘,虽然很多次尝试都失败了,但我们相信,在代码世界一切皆有可能。

让我们先回顾一下理想中的LINQ查询代码:

using (BlogDbContext context = new BlogDbContext())
{
var result
= (from e in context.BlogEntries
join t
in context.PostTexts
on e.ID equals t.ID
where e.ID == entryId
select
new BlogEntry()
{
Title
= e.Title,
Body
= t.Text
})
.FirstOrDefault();
}

再回顾一下错误信息:

System.NotSupportedException :
The entity or complex type
' BlogServer.Data.Provider.BlogEntry '
cannot be constructed
in a LINQ to Entities query.
at System.Data.Objects.ELinq.ExpressionConverter.CheckInitializerType(Type type)

还有BlogDbContext的代码:

public class BlogDbContext : DbContext
{
public DbSet < BlogEntry > BlogEntries { get ; set ; }
}

把这三者联系起来,把问题精简为:如果一个类型(这里是BlogEntry)被注册到DbSet<T>,Enity Framework就会认为这个类型是complex type,在select new时引发异常。而建立一个具有同样属性的类型(前篇随笔中的BlogEntryClone),由于没有被注册到DbSet<T>,则不会引发异常。

本来很单纯的BlogEntry,从DbSet<T>进入Enity Framework,就变成复杂了;而从其他地方进入,依然单纯。很明显,DbSet<T>有问题。

可以猜测DbSet对BlogEntry动了手脚,可能是修改了BlogEntry的类型信息...

所以,要解决的问题变成:DbSet<T>与select new必须要使用不同的类型,而且要共享属性信息。

自然而然,就会想到继承,于是创建了一个继承自BlogEntry的类DerivedBlogEntry试试,代码如下:

public class DerivedBlogEntry : BlogEntry
{
}

然后,将之用于select new,代码如下:

using (BlogDbContext context = new BlogDbContext())
{
var result
= (from e in context.BlogEntries
join t
in context.PostTexts
on e.ID equals t.ID
where e.ID == entryId
select
new DerivedBlogEntry()
{
Title
= e.Title,
Body
= t.Text
}
).FirstOrDefault();
}

结果出现同样的complex type错误。

稍作分析,就能理解为什么还会出现这个错误。由于DbSet<T>对BlogEntry的类型进行了改变,DerivedBlogEntry继承自BlogEntry,自然也会受到影响。

再把我们要解决的问题进一步提炼:DbSet<T>中的类型(BlogEntry1)与select new中的类型(BlogEntry2)要共享属性(必然要存在关联),而且对BlogEntry1类型的修改不能影响到BlogEntry2。

父类虽然可以与子类共享属性,但对父类类型的修改必然会子类,这就是上面遇到的情况。

似乎我们踏破铁鞋也找不到解决方法...

如果将父类与子类使用的位置交换一下,也就是在DbSet<T>中使用DerivedBlogEntry,在select new中使用BlogEntry...

当这个想法闪现出来的,就预感到这就是解决之道,当时真的很兴奋...迫不及待地用代码进行验证,代码如下:

BlogDbContext的代码:

public class BlogDbContext : DbContext
{
public DbSet < DerivedBlogEntry > BlogEntries { get ; set ; }
}

LINQ查询代码:

using (BlogDbContext context = new BlogDbContext())
{
var result
= (from e in context.BlogEntries
join t
in context.PostTexts
on e.ID equals t.ID
where e.ID == entryId
select
new BlogEntry()
{
Title
= e.Title,
Body
= t.Text
}
).FirstOrDefault();
}

当代码测试通过的时候,内心那种美妙的感觉无法用语言去表达...当时很想庆祝一下,于是,把写出这篇博客当作庆祝的方式!

转载于:https://www.cnblogs.com/dudu/archive/2011/04/01/entity_framework_select_new_ok.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值