J4N*_*J4N 51 .net c# sql entity-framework
我正在使用实体框架来连接数据库.我有一个小问题:
我有一个表有一个varbinary(MAX)列(带有文件流).
我正在使用SQL请求来管理"数据"部分,而其余部分则使用EF(文件的元数据).
我有一个代码必须获取文件的所有文件id,文件名,guid,修改日期等.这根本不需要"数据"字段.
有没有办法检索List但没有填充此列?
就像是
context.Files.Where(f=>f.xyz).Exclude(f=>f.Data).ToList();
Run Code Online (Sandbox Code Playgroud)
??
我知道我可以创建匿名对象,但我需要将结果传递给方法,所以没有匿名方法.我不想把它放在匿名类型列表中,然后创建一个非匿名类型(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
};
}
Run Code Online (Sandbox Code Playgroud)
(我在这里使用的是匿名类型,否则你会得到一个NotSupportedException:实体或复杂类型'ProjectName.File'不能在LINQ to Entities查询中构造.)
(例如,此代码抛出先前的异常:
File file2 = context.Files.Where(f => f.Id == idFile)
.Select(f => new File() {Id = f.Id, DataType = f.DataType}).FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)
和"文件"是我得到的类型context.Files.ToList()
.这是好班级:
using File = MyProjectNamespace.Common.Data.DataModel.File;
Run Code Online (Sandbox Code Playgroud)
File是我的EF datacontext的已知类:
public ObjectSet<File> Files
{
get { return _files ?? (_files = CreateObjectSet<File>("Files")); }
}
private ObjectSet<File> _files;
Run Code Online (Sandbox Code Playgroud)
Lad*_*nka 19
有没有办法检索List但没有填充此列?
并非没有您想要避免的投影.如果列已映射,则它是您实体的自然部分.没有此列的实体不完整 - 它是不同的数据集=投影.
我在这里使用匿名类型,否则您将得到NotSupportedException:无法在LINQ to Entities查询中构造实体或复杂类型"ProjectName.File".
异常表示您无法投影到映射的实体.我在上面提到了原因 - 投影使得不同的数据集和EF不喜欢"部分实体".
错误16错误3023:从第2717行开始映射片段时出现问题:表中的Files Files.Data文件必须映射:它没有默认值且不可为空.
从设计师中删除属性是不够的.您必须将EDMX作为XML打开并从SSDL中删除列,这将使您的模型非常脆弱(每次从数据库更新都会使您的列回归).如果您不想映射列,则应使用不带列的数据库视图并映射视图而不是表,但您将无法插入数据.
作为解决所有问题的解决方法,使用表拆分并将有问题的二进制列分离到与主File
实体具有1:1关系的另一个实体.
Yuc*_*uck 11
我会做这样的事情:
var result = from thing in dbContext.Things
select new Thing {
PropertyA = thing.PropertyA,
Another = thing.Another
// and so on, skipping the VarBinary(MAX) property
};
Run Code Online (Sandbox Code Playgroud)
Thing
EF知道如何实现的实体在哪里.生成的SQL语句不应在其结果集中包含大列,因为查询中不需要它.
编辑:从编辑中,您得到错误NotSupportedException:无法在LINQ to Entities查询中构造实体或复杂类型"ProjectName.File".因为您尚未将该类映射为实体.您不能在EF不知道的LINQ to Entities查询中包含对象,并期望它生成适当的SQL语句.
您可以映射VarBinary(MAX)
在其定义中排除列的其他类型,或使用上面的代码.
你可以这样做:
var files = dbContext.Database.SqlQuery<File>("select FileId, DataType, MimeType from Files");
Run Code Online (Sandbox Code Playgroud)
或这个:
var files = objectContext.ExecuteStoreQuery<File>("select FileId, DataType, MimeType from Files");
Run Code Online (Sandbox Code Playgroud)
取决于您的EF版本
我之所以有此要求,是因为我有一个Document
实体,该实体的Content
字段包含文件的内容,即大小为100MB,并且我具有要返回其余列的搜索功能。
我选择使用投影:
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
});
Run Code Online (Sandbox Code Playgroud)
然后我的WebAPI控制器通过这个results
目的是共同的分页功能,它适用一个.Skip
,.Take
和一个.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)
});
Run Code Online (Sandbox Code Playgroud)
然后我返回DTO列表:
return Ok(dtos);
Run Code Online (Sandbox Code Playgroud)
因此,它使用的投影可能不符合原始海报的要求,但是如果您使用的是DTO类,则无论如何都要进行转换。您可以轻松地执行以下操作以将其返回为实际实体:
var dtos = paginated.Select(o => new Document
{
Content = o.Content,
ContentType = o.ContentType,
DocumentTypeId = o.DocumentTypeId,
//...
Run Code Online (Sandbox Code Playgroud)
只需几个额外的步骤,但这对我来说很好。
对于 EF Core 2,我实现了这样的解决方案:
var files = context.Files.AsNoTracking()
.IgnoreProperty(f => f.Report)
.ToList();
Run Code Online (Sandbox Code Playgroud)
基本思想是将例如这个查询:
SELECT [f].[Id], [f].[Report], [f].[CreationDate]
FROM [File] AS [f]
Run Code Online (Sandbox Code Playgroud)
进入这个:
SELECT [f].[Id], '' as [Report], [f].[CreationDate]
FROM [File] AS [f]
Run Code Online (Sandbox Code Playgroud)
你可以在这里看到完整的源代码:https : //github.com/aspnet/EntityFrameworkCore/issues/1387#issuecomment-495630292