EF:获取未在任何地方引用主键的对象列表

时间:2014-04-14 10:55:25

标签: c# entity-framework entity-framework-5

我当前的数据库有一个Files表,由其他几个表引用。我想要实现的是检索一个文件列表,其中根本没有引用主键。

模型的结构如下所示。

public class File
{ 
    public int FileId { get; set; }
    public ......
}
public class AFiles 
{
    public int AFilesId { get; set; }
    [ForeignKey("File")]
    public int FileId { get; set; }
    public virtual File File { get; set; }
    .....
}
public class BFiles 
{
    public int BFilesId { get; set; }
    [ForeignKey("File")]
    public int FileId { get; set; }
    public virtual File File { get; set; }
    .....
}

我一直在尝试的是:

return context.File.Where(x =>
            !context.AFiles.Any(y => y.FileId == x.FileId) &&
            !context.BFiles.Any(y => y.FileId == x.FileId) 
        ).Select(x => x.FileId).ToList();

但这会引发Unable to create a constant value of type 'AFile'. Only primitive types or enumeration types are supported in this context.

的错误

是否有一种优雅的处理方式,我不能只从AFiles和BFiles中提取完整的FileId引用列表,因为这样做太昂贵了。

2 个答案:

答案 0 :(得分:2)

var ids = context.AFiles.Select(af => af.FileId)
                 .Union(context.BFiles.Select(bf => bf.FileId))
                 .Distinct();

var files = context.File.Where(f => !ids.Contains(f.FileId)).ToList();

试试这个

它将导致类似以下内容(SQL Server Profiler)

SELECT 
    [Extent1].[FileId] AS [Id], 
    [Extent1].[Name] AS [Name], 
    FROM [dbo].[File] AS [Extent1]
    WHERE  NOT EXISTS (SELECT 
        1 AS [C1]
        FROM ( SELECT DISTINCT 
            [UnionAll1].[FileId] AS [C1]
            FROM  (SELECT 
                [Extent2].[FileId] AS [FileId] 
                FROM [dbo].[FilesA] AS [Extent2]
            UNION ALL
                SELECT 
                [Extent3].[FileId] AS [FileId]
                FROM [dbo].[FilesB] AS [Extent3]) AS [UnionAll1]
        )  AS [Distinct1]
        WHERE [Distinct1].[C1] = [Extent1].[FileId] 
    )

答案 1 :(得分:1)

这是一个应该执行您想要的任务的查询。

List<int> ids;
using (var context = new Context())
{
    ids = (
        from f in context.Files
        from a in context.AFiles
        from b in context.BFiles
        where a.FileId != f.FileId && b.FileId != f.FileId
        select f.FileId).ToList();
}

public class File {
    [Key] public int FileId { get; set; }    
}
public class AFile {
    [Key] public int AFileId { get; set; }
    [ForeignKey("File")]
    public int FileId { get; set; }
    public virtual File File { get; set; }    
}
public class BFile {
    [Key] public int BFileId { get; set; }
    [ForeignKey("File")]
    public int FileId { get; set; }
    public virtual File File { get; set; }
}

public class Context : DbContext {
    public DbSet<File> Files { get; set; }
    public DbSet<AFile> AFiles { get; set; }
    public DbSet<BFile> BFiles { get; set; }
}

生成的SQL查询

SELECT
    [Filter1].[FileId1] AS [FileId]
    FROM   (SELECT [Extent1].[FileId] AS [FileId1]
        FROM  [dbo].[Files] AS [Extent1]
        CROSS JOIN [dbo].[AFiles] AS [Extent2]
        WHERE [Extent2].[FileId] <> [Extent1].[FileId] ) AS [Filter1]
    CROSS JOIN [dbo].[BFiles] AS [Extent3]
    WHERE [Extent3].[FileId] <> [Filter1].[FileId1]