2012-04-19 37 views
9

是否可以通过对象执行组?实体框架组通过对象或ComplexType

from item in context.Items 
group item by item.MyObject 
select ... 

凡Item.MyObject是一个简单的对象,如:

public class MyObject { 
    public int SomeValue { get; set; } 
    public string SomeName { get; set; } 
    public string SomeOtherProperty { get; set; } 
} 

很显然,我可以做到以下几点:通过对象有很多属性的分组时

from item in context.Items 
group item by new { item.SomeValue, item.SomeName, item.SomeOtherProperty } 
select ... 

然而,这种方法乏味且容易出错。

上述代码产生并显示以下消息NotSupportedException异常:“对于该呼叫到‘的GroupBy’方法的关键选择器类型不是在底层存储提供可比”。重写Equals和GetHashcode没有任何作用。我猜测真正的问题是实体框架不知道如何表达SQL ...?

+0

“MyObject”是EF模型的一部分吗?我可以用'MyObject'(其中MyObject:Item是n:1)上的导航属性做类似的事情。生成的SQL非常糟糕,但至少可以工作。 – 2012-04-21 10:51:48

+0

它实际上是一个ComplexType。所以简而言之,EF意识到对象类型。因为所有的属性实际上都存在于同一个表中,所以我期望得到的SQL比使用导航属性更清晰(如果我当然可以得到它的话) – mindlessgoods 2012-04-21 16:26:19

回答

7

可惜,没有,你不能这样做。 ComplexType看起来很有前途,并且似乎是一个很好的“专栏组” - 但EF团队只是简单地将它设计为完全用于其他用途,并且与将其用作“组列”相关的大量功能完全缺失。

据我所知跨越中,“很明显,我可以做到以下几点:”可能是唯一的出路。您只需要在每个子列的基础上定义分组,或者通过对数据库知道如何比较的某种类型进行投影。

的核心问题是,EF团队看到的ComplexType 不是作为一个群体,使您可以整理你的实体许多领域列的,但是,对他们来说,它是另一种类型的实体,种一个短暂的。 ComplexType旨在表示从存储过程(或表返回函数)返回的对象,该对象返回无法映射到任何常规现有表/类的5列结果集。例如,假设您有一个包含50列/字段的表/类Customer,其中大多数不为空并表示一些敏感数据。您创建一个存储过程,该存储过程将获取客户的ID并返回其{名称,地址,联系电话,鞋号}。显然,如果设置了这样的修剪结果,则无法将其解码/映射到具有大量字段的Customer类,而不能将设为null。那么你如何在EF中表示结果集?

第一个选项,相当瘸一条,就是简单地忽略EF和直接对话,以数据库和读/转换/手动解压行/列。那么,我们知道SqlClient,我们可以做到这一点。

第二个选项,很丑陋的一个,是在EF中定义一个存根表/视图,例如CustomerView,它只包含那个{姓名,地址,联系电话,鞋大小}列,并映射存储过程结果集到它。这将很好地工作,但是如果你不小心“生成数据库”形成EF模型,你将获得额外的未使用的表也..

第三种选择救援是的ComplexType。而不是试图做一个影子表或视图,你只需告诉EF,“有一个一些额外的数据类型”是将永远不会被映射到它自己的表,也永远不会有一个PrimaryKey的定义,和EF会为了方便您将它映射到像其他任何数据对象一样的类。现在,有了这样的类型,你可以从程序中返回它并将其作为一个很好的类型对象来检索它,你可以把它作为过程的参数传递给它,等等。但是:你不能自己坚持它。它没有自己的表映射,也没有自己的主键。它有没有标识

这很好,但是,为什么你想从程序返回这样的数据类型?可能是程序处理或生成了一些数据,并且您想在某个表中存储它们。你还没有定义一个完整的普通实体,所以事物只是一个'数据包',所以你可能会将结果值和其他数据一起写入该表。这就是为什么EF允许您将ComplexType映射到表的某些列:如果您从某个过程中获得了该临时结果对象,并且现在想要将它写入某处,则不必一个接一个地手动执行,您只需将其映射到客户的“姓名,地址,联系电话,鞋号”栏即可。

最重要的一点是,数据库服务器永远不知道这样的ComplexType存在。正如我所说,它没有身份。当你尝试做一个LINQ查询像

aset.Where(item => item.complexProperty == complexValue) 

届时,复数值是不映射到任何表CLR对象,没有标识,因此没有PK,从而EF已经完全不知道如何检查是否“左手对象”与“右手对象”相同。如果对象有一些身份定义,它可以检查服务器端的PK,或者在客户端进行对象引用比较,但在这里 - 它只是失败。

我完全同意这是EF中缺少的另一个该死的有用功能。我相信英孚团队在逐列比较复杂类型的过程中会非常容易,但他们没有。他们根本没有想到ComplexTypes可以用来整理表格。它们意味着它是一个瞬时数据包,可以传递到存储过程和函数。可惜。

+0

附注:我说的是比较,因为当我试图过滤复杂类型时,我最近偶然发现了这一点。分组是不同的,这一切归结为'不知道如何比较'的问题。如果有人知道任何解决方法或EF扩展 - 我会很高兴知道它。至于现在,我只找到说'对不起,这是不可用的,可能在EF5'' – quetzalcoatl 2012-04-24 21:55:32

+0

感谢您的深入解答 - 这是另一个功能,这将是很好的未来版本中看到的文章。 – mindlessgoods 2012-04-24 23:30:06