c# - 如何在 Linq-to-SQL 实体类中创建自定义属性?

标签 c# linq-to-sql

我有两个表 Studies 和 Series。系列 FK'd 回到研究,因此一项研究包含可变数量的系列。 每个 Series 项目都有一个 Deleted 列,表明它已从数据库中逻辑删除。

我正在尝试在 Study 类中实现一个 Deleted 属性,该属性仅在删除所有包含的 Series 时才返回 true。 我正在使用 O/R Designer 生成的类,因此我将以下内容添加到 Study 类型的用户可修改分部类中:

public bool Deleted
{
    get
    {
        var nonDeletedSeries = from s in Series
                               where !s.Deleted
                               select s;
        return nonDeletedSeries.Count() == 0;
    }
    set
    {
        foreach (var series in Series)
        {
            series.Deleted = value;
        }
    }
}

这给出了一个异常“成员‘PiccoloDatabase.Study.Deleted’没有支持的 SQL 转换。”当执行这个调用 get 的简单查询时:

IQueryable<Study> dataQuery = dbCtxt.Studies;
dataQuery = dataQuery.Where((s) => !s.Deleted);
foreach (var study in dataQuery)
{
   ...
}

基于此http://www.foliotek.com/devblog/using-custom-properties-inside-linq-to-sql-queries/ ,我尝试了以下方法:

static Expression<Func<Study, bool>> DeletedExpr = t => false;
public bool Deleted
{
    get
    {
        var nameFunc = DeletedExpr.Compile();
        return nameFunc(this);
    }
    set
    {  ... same as before
    }
}

当运行查询时,我遇到了同样的异常,即没有支持的 SQL 转换。 ( lambda 表达式的逻辑还无关紧要 - 只是试图绕过异常。)

我是否遗漏了一些基本属性或允许转换为 SQL 的内容?我已经阅读了 SO 上关于此异常的大部分帖子,但似乎没有任何内容完全适合我的情况。

最佳答案

我相信 LINQ-to-SQL 的要点是您的实体已为您映射并且必须在数据库中具有相关性。看来您正在尝试混合使用 LINQ-to-Objects 和 LINQ-to-SQL。

如果 Series 表在数据库中有 Deleted 字段,而 Study 表没有,但您想将逻辑 Study.Deleted 转换为 SQL,那么扩展将是一种方法。

public static class StudyExtensions
{
    public static IQueryable<study> AllDeleted(this IQueryable<study> studies)
    {
        return studies.Where(study => !study.series.Any(series => !series.deleted));
    }
}

class Program
{
    public static void Main()
    {
        DBDataContext db = new DBDataContext();
        db.Log = Console.Out;

        var deletedStudies = 
            from study in db.studies.AllDeleted()
            select study;

        foreach (var study in deletedStudies)
        {
            Console.WriteLine(study.name);
        }
    }
}

这会将您的“已删除研究”表达式映射到 SQL 中:

SELECT t0.study_id, t0.name
FROM study AS t0
WHERE NOT EXISTS(
    SELECT NULL AS EMPTY
    FROM series AS t1
    WHERE (NOT (t1.deleted = 1)) AND (t1.fk_study_id = t0.study_id)
)

或者,您可以构建实际的表达式并将它们注入(inject)到您的查询中,但这是一种矫枉过正的做法。

但是,如果 Series 和 Study 在数据库中都没有 Deleted 字段,而只在内存中,那么您需要先将查询转换为 IEnumerable,然后才能访问 Deleted 属性。然而,这样做会在应用谓词之前将记录传输到内存中,并且可能会很昂贵。即

var deletedStudies = 
    from study in db.studies.ToList()
    where study.Deleted
    select study;

foreach (var study in deletedStudies)
{
    Console.WriteLine(study.name);
}

关于c# - 如何在 Linq-to-SQL 实体类中创建自定义属性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11526377/

相关文章:

c# - 泛型类中的数组和索引器

c# - OData v4 函数总是返回 404

c# - 数据库设计头脑 Storm : Sale Prices

c# - 比较具有不同 'times' 的 DateTime 字段

c# - 页面继承

c# - 如何模拟 Asp.net 身份 UserManager 的 CreateAsync 方法

c# - 在 Irony 中定义常量和运算符

c# - 如何使用递归编程填充包含多个类别的列表框

c# - Linq To Sql - 当另一个值更改时更新一个值

c# - 从 LINQ DataContext 中的表名获取表数据