C# LINQ to SQL:重构此通用 GetByID 方法

2024-04-18

我写了下面的方法。

public T GetByID(int id)
{
    var dbcontext = DB;
    var table = dbcontext.GetTable<T>();
    return table.ToList().SingleOrDefault(e => Convert.ToInt16(e.GetType().GetProperties().First().GetValue(e, null)) == id);
}

基本上它是通用类中的一个方法,其中T是 DataContext 中的一个类。

该方法从 T 的类型获取表(GetTable)并检查输入参数的第一个属性(始终是 ID)。

问题是我必须首先将元素表转换为列表才能执行GetType属性上,但这不是很方便,因为必须枚举表的所有元素并将其转换为List.

我如何重构这个方法以避免ToList整个桌子上?

[Update]

我无法执行的原因Where直接在桌子上是因为我收到这个异常:

方法“System.Reflection.PropertyInfo[] GetProperties()”不支持对 SQL 的转换。

Because GetProperties无法翻译成SQL。

[Update]

有些人建议使用接口T,但问题是T参数将是自动生成的类[DataContextName].designer.cs,因此我无法让它实现一个接口(并且实现 LINQ 的所有这些“数据库类”的接口是不可行的;而且,一旦我向 DataContext 添加新表,该文件就会重新生成,从而丢失所有写入的内容数据)。

因此,必须有更好的方法来做到这一点......

[Update]

我现在已经实现了我的代码尼尔·威廉姆斯 https://stackoverflow.com/questions/735140/c-linq-to-sql-refectoring-this-generic-getbyid-method/735209#735209'建议,但我仍然遇到问题。以下是代码摘录:

界面:

public interface IHasID
{
    int ID { get; set; }
}

数据上下文[查看代码]:

namespace MusicRepo_DataContext
{
    partial class Artist : IHasID
    {
        public int ID
        {
            get { return ArtistID; }
            set { throw new System.NotImplementedException(); }
        }
    }
}

通用方法:

public class DBAccess<T> where T :  class, IHasID,new()
{
    public T GetByID(int id)
    {
        var dbcontext = DB;
        var table = dbcontext.GetTable<T>();

        return table.SingleOrDefault(e => e.ID.Equals(id));
    }
}

该行抛出异常:return table.SingleOrDefault(e => e.ID.Equals(id));例外是:

System.NotSupportedException: The member 'MusicRepo_DataContext.IHasID.ID' has no supported translation to SQL.

[更新]解决方案:

在...的帮助下丹尼斯·特罗尔 https://stackoverflow.com/questions/735140/c-linq-to-sql-refectoring-this-generic-getbyid-method/735888#735888的发布答案以及该帖子的链接代码咆哮博客 http://mikehadlow.blogspot.com/2008/03/using-irepository-pattern-with-linq-to.html,我终于找到了解决方案:

public static PropertyInfo GetPrimaryKey(this Type entityType)
{
    foreach (PropertyInfo property in entityType.GetProperties())
    {
        ColumnAttribute[] attributes = (ColumnAttribute[])property.GetCustomAttributes(typeof(ColumnAttribute), true);
        if (attributes.Length == 1)
        {
            ColumnAttribute columnAttribute = attributes[0];
            if (columnAttribute.IsPrimaryKey)
            {
                if (property.PropertyType != typeof(int))
                {
                    throw new ApplicationException(string.Format("Primary key, '{0}', of type '{1}' is not int",
                                property.Name, entityType));
                }
                return property;
            }
        }
    }
    throw new ApplicationException(string.Format("No primary key defined for type {0}", entityType.Name));
}

public T GetByID(int id)
{
    var dbcontext = DB;

    var itemParameter = Expression.Parameter(typeof (T), "item");
    var whereExpression = Expression.Lambda<Func<T, bool>>
        (
        Expression.Equal(
            Expression.Property(
                 itemParameter,
                 typeof (T).GetPrimaryKey().Name
                 ),
            Expression.Constant(id)
            ),
        new[] {itemParameter}
        );
    return dbcontext.GetTable<T>().Where(whereExpression).Single();
}

您需要的是构建一个表达式树LINQ 到 SQL http://en.wikipedia.org/wiki/Language_Integrated_Query#LINQ_to_SQL可以理解。假设您的“id”属性始终命名为“id”:

public virtual T GetById<T>(short id)
{
    var itemParameter = Expression.Parameter(typeof(T), "item");
    var whereExpression = Expression.Lambda<Func<T, bool>>
        (
        Expression.Equal(
            Expression.Property(
                itemParameter,
                "id"
                ),
            Expression.Constant(id)
            ),
        new[] { itemParameter }
        );
    var table = DB.GetTable<T>();
    return table.Where(whereExpression).Single();
}

这应该可以解决问题。被无耻地借用了这个博客 http://mikehadlow.blogspot.com/2008/03/using-irepository-pattern-with-linq-to.html。 当您编写如下查询时,这基本上就是 LINQ to SQL 所做的事情

var Q = from t in Context.GetTable<T)()
        where t.id == id
        select t;

您只需为 LTS 做这些工作,因为编译器无法为您创建它,因为没有任何东西可以强制 T 具有“id”属性,并且您无法将任意“id”属性从接口映射到数据库。

====更新====

好的,这是查找主键名称的一个简单实现,假设只有一个(不是复合主键),并且假设所有类型都很好(也就是说,您的主键与您的“短”类型兼容)在 GetById 函数中使用):

public virtual T GetById<T>(short id)
{
    var itemParameter = Expression.Parameter(typeof(T), "item");
    var whereExpression = Expression.Lambda<Func<T, bool>>
        (
        Expression.Equal(
            Expression.Property(
                itemParameter,
                GetPrimaryKeyName<T>()
                ),
            Expression.Constant(id)
            ),
        new[] { itemParameter }
        );
    var table = DB.GetTable<T>();
    return table.Where(whereExpression).Single();
}


public string GetPrimaryKeyName<T>()
{
    var type = Mapping.GetMetaType(typeof(T));

    var PK = (from m in type.DataMembers
              where m.IsPrimaryKey
              select m).Single();
    return PK.Name;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C# LINQ to SQL:重构此通用 GetByID 方法 的相关文章

  • WebClient.DownloadDataAsync 冻结了我的 UI

    我在 Form 构造函数中的 InitializeComponent 之后有以下代码 using WebClient client new WebClient client DownloadDataCompleted new Downloa
  • 并行化斐波那契序列生成器

    我正在学习并行化 在一项练习中 我得到了一些我应该提高性能的算法 其中之一是斐波那契数列生成器 array 0 0 array 1 1 for q 2 q lt MAX q array q array q 1 array q 2 我怀疑 这
  • C# 处理标准输入

    我目前正在尝试通过命令行断开与网络文件夹的连接 并使用以下代码 System Diagnostics Process process2 new System Diagnostics Process System Diagnostics Pr
  • 在 C++11 中移出 stdpriority_queue 的元素

    最小的工作示例 include
  • 在 C# 中何时使用 ArrayList 而不是 array[]?

    我经常使用一个ArrayList而不是 正常 array 当我使用时 我感觉好像我在作弊 或懒惰 ArrayList 什么时候可以使用ArrayList在数组上 数组是强类型的 并且可以很好地用作参数 如果您知道集合的长度并且它是固定的 则
  • 用于连接 DataTable 上的动态列的动态 LINQ

    我目前遇到的情况不确定如何继续 我有两个从数据库填充的数据表 我还有一个可用的列名称列表 可用于将这两个数据表连接在一起 我希望编写一组 LINQ 查询 这些查询将 显示两个数据表中的行 内部联接 用于从一个数据表更新另一个数据表 显示一个
  • 如何使用递归查找数字中的最小元素 [C]

    好的 所以我正在准备我的 C 考试 当谈到递归时我有点卡住了我是大学一年级的学生 这对我来说似乎有点困难 练习要求在给定的数字中使用递归函数我需要找到最小的元素 例如 52873 是 2 程序需要打印 2 include
  • Xamarin - SignalR 挂在连接上

    我正在尝试将我的 Xamarin 应用程序连接到托管在 Azure 上的 SignalR 后端 我遇到的问题是每次我在 HubConnection 上调用 StartAsync 时 它都会挂起客户端并且请求永远不会完成 我尝试通过应用程序进
  • 时间:2019-03-17 标签:c++fstream并发访问

    如果从不同的进程 线程同时访问文件会发生什么 据我所知 没有锁定文件的标准方法 只有操作系统特定的功能 就我而言 文件将被经常读取而很少写入 现在如果A打开一个文件进行读取 ifstream 并开始读取块 和B打开相同的文件进行写入 ofs
  • Resharper:IEnumerable 的可能多重枚举

    我正在使用新的 Resharper 版本 6 在我的代码中的几个地方 它给一些文本加了下划线 并警告我可能存在IEnumerable 可能的多重枚举 我理解这意味着什么 并在适当的情况下采纳了建议 但在某些情况下 我不确定这实际上是一个大问
  • 将错误代码映射到 C++ 中的字符串

    将错误代码从枚举映射到字符串的更有效方法是什么 在 C 中 例如 现在我正在做这样的事情 std string ErrorCodeToString enum errorCode switch errorCode case ERROR ONE
  • doxygen c++:记录由“using”声明公开的私有继承成员

    作为一个例子 我有以下课程 class A public void methodOne class B private A public Brief description using A methodOne 我还没有找到强制 doxyge
  • IronPython 中批量求值表达式的性能

    在 C 4 0 应用程序中 我有一个具有相同长度的强类型 IList 的字典 一个基于动态强类型列的表 我希望用户根据将在所有行上聚合的可用列提供一个或多个 python 表达式 在静态上下文中它将是 IDictionary
  • 在哪里可以下载没有 Visual Studio 2010 的 C# 4.0 编译器?

    我知道 CTP VS 2010 映像 但我可以只下载 NET Framework 4 0 和 C 编译器吗 AFAIK VS 2010 CTP 仅作为 VM 映像提供 我不相信 Microsoft 发布了 VS 的安装程序 其中一个绝对不适
  • 有没有办法直接在函数参数中格式化字符串而不是使用临时字符串?

    我有一个接受字符串 字符数组 作为参数的函数 void enterString char my string 当使用这个函数时 我经常发现自己想要输入格式化的字符串 我使用 sprintf 来做到这一点 然而 我每次都必须创建一个临时字符串
  • “必须声明标量变量”错误[重复]

    这个问题在这里已经有答案了 必须声明标量变量 Id SqlConnection con new SqlConnection connectionstring con Open SqlCommand cmd new SqlCommand cm
  • printf或iostream如何指定点后的最大位数

    字符串采用什么格式printf or iomanip我应该使用 iostream 中的运算符以以下格式打印浮点数 125 0 gt 125 125 1 gt 125 1 125 12312 gt 125 12 1 12345 gt 1 12
  • 将 char 绑定到枚举类型

    我有一段与此非常相似的代码 class someclass public enum Section START MID END vector section Full void ex for int i 0 i section
  • 为什么表达式 a = a + b - ( b = a ) 在 C++ 中给出序列点警告?

    以下是测试代码 int main int a 3 int b 4 a a b b a cout lt lt a lt lt a lt lt lt lt b lt lt b lt lt n return 0 编译此命令会出现以下警告 gt g
  • 嵌入式二进制资源 - 如何枚举嵌入的图像文件?

    我按照中的说明进行操作这本书 http www apress com book view 9781430225492 关于资源等的章节 我不太明白的是 如何替换它 images Add new BitmapImage new Uri Ima

随机推荐

  • Rails respond_with:它是如何工作的?

    我到处读到关于它有多酷的内容respond with方法在 Rails 3 中 但我什至无法在 Rails API 中或通过搜索源代码找到对它的引用 任何人都可以向我解释它是如何工作的 您可以使用哪些选项等 或者向我指出它实际实现的位置 以
  • 在事务结束时发送事件

    我有一个服务对象的接口 如下所示 为简洁起见进行了简化 public interface ItemService public Item getItemById String itemId int version public void c
  • 部署到 Docker 时外部化 Spring Boot 属性

    在我的 Spring Boot 应用程序中 我想将属性外部化以在 Docker 容器中运行 首次部署时 当前的属性my server src main resources application yml由应用程序按预期加载和使用 一切正常
  • 如何修复这个已有 8 年历史的 VBA 64 位编译器错误?

    所以这就是错误 64 BitVBA主机 例如Access 365 64位或Excel 2016 64位 创建类模块SomeClass this needs to be here to trigger the bug Private Sub
  • Hashmap 单键保存一个类。计算密钥并检索计数器

    我正在开发一个数据库自我项目 我有一个来自以下位置的输入文件 http ir dcs gla ac uk resources test collections cran http ir dcs gla ac uk resources tes
  • 将数据表保存到文本文件的最短方法

    我刚刚找到了一些答案 但发现它们都非常长并且有很多迭代 所以我想出了自己的解决方案 将表转换为字符串 string myTableAsString String Join Environment NewLine myDataTable Ro
  • JavaScript 中的封装

    很久以前 我看到有人用如下代码封装了整个 JavaScript 块 function this 问题 上面的代码正确吗 像上面提到的那样封装整个 JavaScript 块有什么好处 对 那是正确的 它称为自调用匿名函数表达式 JavaScr
  • SQL Server DateTime 参数“舍入”警告

    与其说是问题 不如说是警告 今天早上我们解决了一个非常令人费解的错误 我们有各种报告 允许用户输入他们想要运行的日期范围 假设是 如果您要求提供 2010 年 8 月 1 日至 2010 年 8 月 10 日的报告 您的意思是include
  • android内容提供者总和查询

    是否可以使用getContentResolver query 当我想要的时候sum column OR 我是否必须对数据库句柄进行原始查询 当提供列数组时ContentResolver query 将列名称括起来sum 功能 String
  • 将python程序转换为windows可执行文件

    我正在尝试从具有 GUI 的 python 程序创建 Windows 可执行文件 我正在使用以下脚本 from distutils core import setup import py2exe setup console gui py 它
  • Typescript 阻止节点/模块工厂模式:错误 TS4060

    当使用 ES6 模块语法导出返回 Typescript 类实例的工厂函数时 会产生以下错误 错误 TS4060 导出函数的返回类型具有或正在使用私有名称 Paths 来自 paths ts Class scoped behind the e
  • Google Map API 通过邮政编码获取地址信息,但它通过街道号码响应结果

    我正在使用谷歌地图 API 通过世界各地的邮政编码获取地址信息 非特定国家 地区 我预计邮政编码是 610 但 google 响应结果是街道号码 610 有什么方法可以仅通过邮政编码获取地址吗 预先感谢各位的支持 与此查询一起进行的操作怎么
  • 如何在 SVG 中制作不同大小的内嵌文本?

    在 HTML 中为不同的单词创建具有不同字体大小的文本非常容易 但是关于
  • for(:) 在 Java 中是什么意思?

    package MyTest import java beans BeanInfo import java beans Introspector import java beans PropertyDescriptor class Pers
  • JTextField设置输入限制

    您好 我正在尝试使用 setDocument 方法来限制用户可以在文本字段中输入的字符数 但不知怎的 它并没有限制输入字符的数量 这是代码 import javax swing text AttributeSet import javax
  • 从加载的信息中计算出值

    我需要能够为用户进行的每个赌注显示 动态回报 但由于某种原因 它们都不起作用 我以前曾问过这个问题 但没有运气 我希望其中的额外细节足以帮助您最终找到答案 我已经对其中一个脚本进行了硬编码 以便使用odds 1 stake 1等等 这有效
  • :hover 仅适用于rotateX 转换后的div 的下部

    我有一个 div 并应用了 CSSrotateX 变换 webkit transform perspective 500px rotateX 60deg rotateY 60deg 一堆较小的 div 漂浮在其中 并应用 hover 规则
  • MATLAB 写入多页 tiff 指数慢

    我正在尝试编写一个多页 tiff 文件 该文件是 128 像素 x 128 像素 x 122000 帧的 16 位无符号整数 ImageJ 或简短的 Python 脚本可以在快速机器上在一分钟内完成此操作 在同一台机器上 无论使用我尝试过的
  • 使用 TIMEZONE 查询 Oracle TIMESTAMP

    我在 Oracle DB 表中有一个类型为TIMESTAMP 6 WITH TIME ZONE 有些数据行包含来自不同时区的数据 有些是 UTC 有些是其他时区偏移量 有没有一种方法可以查询 Oracle 表 以便结果始终以 UTC 形式返
  • C# LINQ to SQL:重构此通用 GetByID 方法

    我写了下面的方法 public T GetByID int id var dbcontext DB var table dbcontext GetTable