从一个没有ONE字段的entityframework中检索一个对象

我正在使用entity framework来连接数据库。 我有一个小问题:

我有一个表有一个varbinary(MAX)列(文件stream)。

我使用SQL请求来pipe理“数据”部分,但其余的EF(文件的元数据)。

我有一个代码,必须获得文件的所有文件ID,文件名,GUID,修改date…。 这根本不需要“数据”字段。

有没有办法检索一个列表,但没有填写这个列?

就像是

context.Files.Where(f=>f.xyz).Exclude(f=>f.Data).ToList(); 

??

我知道我可以创build匿名对象,但是我需要将结果传递给一个方法,所以没有匿名方法。 我不想把它放在一个匿名types列表中,然后创build一个非匿名types(File)的列表。

目标是避免这种情况:

 using(RsSolutionsEntities context = new RsSolutionsEntities()) { var file = context.Files .Where(f => f.Id == idFile) .Select(f => new { f.Id, f.MimeType, f.Size, f.FileName, f.DataType, f.DateModification, f.FileId }).FirstOrDefault(); return new File() { DataType = file.DataType, DateModification = file.DateModification, FileId = file.FileId, FileName = file.FileName, Id = file.Id, MimeType = file.MimeType, Size = file.Size }; } 

(我在这里使用的匿名types,否则你会得到一个NotSupportedException:实体或复杂types'ProjectName.File'不能在LINQ to Entities查询中构造。

(例如,这个代码抛出了以前的exception:

 File file2 = context.Files.Where(f => f.Id == idFile) .Select(f => new File() {Id = f.Id, DataType = f.DataType}).FirstOrDefault(); 

和“文件”是我得到一个context.Files.ToList()的types。 这是一个好class级:

 using File = MyProjectNamespace.Common.Data.DataModel.File; 

文件是我的EF datacontext的一个已知的类:

 public ObjectSet<File> Files { get { return _files ?? (_files = CreateObjectSet<File>("Files")); } } private ObjectSet<File> _files; 

有没有办法检索一个列表,但没有填写这个列?

不是没有你想避免的投影。 如果该列被映射,则它是您的实体的自然部分。 没有这个列的实体不完整 – 它是不同的数据集=投影。

我在这里使用的匿名types,否则你会得到一个NotSupportedException:实体或复杂types“ProjectName.File”不能在LINQ to Entities查询中构造。

作为例外说你不能投影到映射的实体。 我上面提到的原因 – 投影做了不同的数据集,EF不喜欢“部分实体”。

错误16错误3023:从行2717开始映射片段中的问题:表文件中的列Files.Data必须被映射:它没有默认值,并且不可为空。

从devise师身上删除财产是不够的。 您必须打开EDMX作为XML并从SSDL删除列,这将使您的模型非常脆弱(从数据库的每个更新将把您的列回)。 如果您不想映射列,则应使用不带列的数据库视图,并映射视图而不是表格,但不能插入数据。

作为解决所有问题的一种解决方法,使用表格拆分并将有问题的二进制列与1:1关系分隔到另一个实体,以便与您的主File实体关联。

我会做这样的事情:

 var result = from thing in dbContext.Things select new Thing { PropertyA = thing.PropertyA, Another = thing.Another // and so on, skipping the VarBinary(MAX) property }; 

凡是EF知道如何实现的实体。 生成的SQL语句不应在其结果集中包含较大的列,因为查询中不需要该列。

编辑 :从您的编辑,你会得到错误NotSupportedException:实体或复杂types“ProjectName.File”不能在LINQ to Entities查询中构造。 因为您还没有将该类映射为实体。 您不能将LINQ中的对象包含到EF不知道的实体查询中,并期望它生成适当的SQL语句。

您可以映射排除其定义中的VarBinary(MAX)列的其他types或使用上面的代码。

你可以这样做:

 var files = dbContext.Database.SqlQuery<File>("select FileId, DataType, MimeType from Files"); 

或这个:

 var files = objectContext.ExecuteStoreQuery<File>("select FileId, DataType, MimeType from Files"); 

取决于您的EF版本

我有这样的要求,因为我有一个Document实体有一个Content字段与文件的内容,即100MB大小,我有一个searchfunction,我想返回其余的列。

我select使用投影:

 IQueryable<Document> results = dbContext.Documents.Include(o => o.UploadedBy).Select(o => new { Content = (string)null, ContentType = o.ContentType, DocumentTypeId = o.DocumentTypeId, FileName = o.FileName, Id = o.Id, // etc. even with related entities here like: UploadedBy = o.UploadedBy }); 

然后我的WebApi控制器将这个results对象传递给一个通用的分页函数,该函数应用了.Skip.ToList.ToList

这意味着当查询被执行时,它不访问Content列,所以100MB的数据没有被触及,查询速度就像你期望的那样快。

接下来,我把它放回到我的DTO类中,在这种情况下,它与实体类几乎完全相同,所以这可能不是您需要实现的步骤,但它遵循我典型的WebApi编码模式,因此:

 var dtos = paginated.Select(o => new DocumentDTO { Content = o.Content, ContentType = o.ContentType, DocumentTypeId = o.DocumentTypeId, FileName = o.FileName, Id = o.Id, UploadedBy = o.UploadedBy == null ? null : ModelFactory.Create(o.UploadedBy) }); 

然后我返回DTO列表:

 return Ok(dtos); 

所以它使用的投影,可能不符合原来的海报的要求,但如果你正在使用DTO类,无论如何你正在转换。 你可以简单地做到以下几点,将它们作为实际的实体返回:

 var dtos = paginated.Select(o => new Document { Content = o.Content, ContentType = o.ContentType, DocumentTypeId = o.DocumentTypeId, //... 

只是几个额外的步骤,但这对我来说很好。

我想分享我的努力,以解决这个问题,以防其他人处于相同的情况。

我从丹尼尔 ( Jeremy Danyow)的build议开始,对我来说这是不那么痛苦的select。

 // You need to include all fields in the query, just make null the ones you don't want. var results = context.Database.SqlQuery<myEntity>("SELECT Field1, Field2, Field3, HugeField4 = NULL, Field5 FROM TableName"); 

在我的情况下,我需要一个IQueryable<>结果对象,所以我最后添加了AsQueryable() 。 这当然让我加上电话,其中,我们都知道,其他的命令,他们工作得很好。 但有一个警告:

正常的代码(基本上context.myEntity.AsQueryable() )返回一个System.Data.Entity.DbSet<Data.DataModel.myEntity> ,而这种方法返回System.Linq.EnumerableQuery<Data.DataModel.myEntity>

显然,这意味着我的自定义查询按照“按原样”立即执行,稍后添加的过滤将在后面完成,而不是在数据库中完成。

因此,我试图通过使用EF创build的确切查询来模仿entity framework的对象,即使是那些[Extent1]别名,但它不起作用。 分析结果对象时,其查询结束

FROM [dbo].[TableName] AS [Extent1].Where(c => ...

而不是预期的

FROM [dbo].[TableName] AS [Extent1] WHERE ([Extent1]...

无论如何,这个工作,只要桌子不是很大,这个方法就够快了。 否则,您没有办法通过连接string手动添加条件,如传统的dynamicSQL。 一个非常基本的例子,如果你不知道我在说什么:

 string query = "SELECT Field1, Field2, Field3, HugeField4 = NULL, Field5 FROM TableName"; if (parameterId.HasValue) query += " WHERE Field1 = " + parameterId.Value.ToString(); var results = context.Database.SqlQuery<myEntity>(query); 

如果你的方法有时需要这个字段,你可以添加一个bool参数,然后做这样的事情:

 IQueryable<myEntity> results; if (excludeBigData) results = context.Database.SqlQuery<myEntity>("SELECT Field1, Field2, Field3, HugeField4 = NULL, Field5 FROM TableName").AsQueryable(); else results = context.myEntity.AsQueryable(); 

如果任何人设法使Linq扩展正常工作,就像它是最初的EF对象一样,请注释,以便我可以更新答案。

我试过这个:

从edmx图(EF 6)中,我点击了我想要从EF隐藏的列和他们的属性,你可以将他们的getter和setter设置为private。 这样,对我来说,它的工作。

我返回一些包含用户引用的数据,所以我想隐藏密码字段,即使它被encryption和腌制,我只是不希望它在我的JSON,我不想做一个:

 Select(col => new {}) 

因为这是一个很难创build和维护,特别是对于有很多关系的大桌子。

这种方法的缺点是,如果你重新生成你的模型,你将需要再次修改他们的getter和setter。