jjzjj

c# - 在 C# 中扩展 DataTable

coder 2024-05-26 原文

类的静态构造函数 SourceManager遍历所有模块/类并发现所有实现 ISource 的类.它将实例化其中的每一个并公开一个 IEnumerable。它们作为一个名为 IEnumerable<ISource> Sources 的静态属性.为简单起见 ISource有两个属性,DataTable Table { get; }string UniqueName { get; } .实例化时各不相同ISource负责填充其 Table来自 SQL、MDX 等。对于所有 ISource到目前为止,我已经写好了,正在加载 Table所有 DataRow s 实例化时已经足够了。然而,我现在有一种情况,我想加载 TableDataRow是懒惰的,而不是全部在前面。我该怎么做?我将通过一个例子来说明。

PermissionSource工具 ISource .它的Table属性,具有 private set的值为 new PermissionDataTable() .它的UniqueName"Permissions" .截至目前,没有权限从数据库加载到此 Table属性(property)。

ISource permissionSource = SourceManager.Sources.
    Where(s => "Permission".Equals(s.UniqueName)).First();

现在我们已经获得了PermissionSource ,而是通过一个接口(interface)。让我们获得许可。

DataRow row = permissionSource.Table.Rows.Cast<DataRow>().
    Where(r => r["PermissionName"].Equals("PermissionName")).First()

我已经覆盖了 Rows属性(property) PermissionDataTable这样上面的代码就以某种方式获得了与 "PermissionName" 关联的权限的值。在数据库中。其他权限未加载。

我在权限系统中没有选择,我也没有选择不使用 DataTable .

编辑:

在我的示例中,我需要覆盖 Rows DataTable的属性(property). Rows , 不过, 是 DataRowCollection这是 sealed .因此,就创建一个像我想做的那样的最小自定义 DataTable 实现而言,可以做的事情并不多。

最佳答案

我不确定我是否理解您在使用 DataTable 时的限制,但是我过去在需要“刷新”DataTable 中的数据或使用不同的标准重新填充数据时做过的一件事是创建一个新类派生自 DataTable,其中包括对 DataAdapter 的引用以及最初用于填充 DataTable 的连接和选择信息。

例如,DataTable 子类可能类似于下面的 LazyDataTable 代码。请注意,我添加了几种不同的访问行的方法。在查看接近本文末尾的 PermissionSource 和主要 Program 代码后,它们可能更有意义。 另外,请注意,我并没有包括在每种情况下正确打开和关闭数据库连接的所有细节。您如何处理这取决于您的数据库访问模型(例如连接池、共享连接等)。

//using System.Data.Common;
public class LazyDataTable : DataTable {
    protected DbDataAdapter Adapter { get; set; }

    public LazyDataTable(DbDataAdapter a) {
        Adapter = a;
    }
    /// <summary>
    /// Save changes back to the database, using the DataAdapter
    /// </summary>
    public void Update() {
        Adapter.Update(this);
    }
    /// <summary>
    /// Fill this datatable using the SelectCommand in the DataAdapter
    /// The DB connection and query have already been set.
    /// </summary>
    public void Fill() {
        Adapter.Fill(this);
    }

    /// <summary>
    /// read and return one row at a time, using IEnumerable syntax
    /// (this example does not actually add the row to this table, 
    /// but that can be done as well, if desired.
    /// </summary>
    public IEnumerable<DataRow> LazyReadRows() {
        using (var reader = OpenReader()) {
            //Get the schema from the reader and copy it to this table.
            var schema = reader.GetSchemaTable();
            var values = new object[schema.Columns.Count];
            while (reader.Read()) {
                reader.GetValues(values);
                var row = schema.NewRow();
                row.ItemArray = values;
                yield return row;
            }
        }
    }

    /// <summary>
    /// Fill one row at a time, and return the new row.
    /// </summary>
    public DataRow ReadRow() {
        if (_reader == null || _reader.IsClosed) 
            _reader = OpenReader();
        //Get the schema from the reader and copy it to this table.
        if (this.Columns.Count == 0) 
            this.Columns.AddRange(_reader.GetSchemaTable().Columns.Cast<DataColumn>().ToArray());
        if (!_reader.Read()) {
            _reader.Dispose();
            return null;
        }
        var values = new object[_reader.FieldCount];
        _reader.GetValues(values);
        return this.Rows.Add(values);
    }
    private DbDataReader _reader = null;

    private DbDataReader OpenReader() {
        OpenConnect();
        return Adapter.SelectCommand.ExecuteReader();
    }

    private void OpenConnect() {
        var cn = Adapter.SelectCommand.Connection;
        if (cn.State == ConnectionState.Closed)
            cn.Open();
    }

    /// <summary>
    /// Change a Parameter in the SelectCommand, to filter which rows to retrieve.
    /// </summary>
    public void SetSelectParam(string name, object value) {
        var selparams = Adapter.SelectCommand.Parameters;
        selparams[name].Value = value;
    }
}

然后您的 PermissionSource 将创建一个 LazyDataTable 并适本地设置 DataAdapter(包括连接和 SELECT 命令)。它不会填充 DataTable,而是将其返回为空,稍后由应用程序代码填充。所以你的 PermissionSource 可能类似于下面的代码。我使用 System.Data.OleDb 数据对象作为示例,但您可以使用所需的任何 ADO 提供程序。

interface ISource {
    public DataTable Table { get; }
    string UniqueName { get; }
}

public class PermissionSource : ISource {
    /// <summary>
    /// Loads a DataTable with all of the information to load it lazily.
    /// </summary>
    public DataTable Table { 
        get { 
            const string SELECT_CMD = "SELECT * FROM [Permissions] WHERE ([PermissionName] IS NULL OR [PermissionName]=@p1) AND [OtherProperty]=@p2";
            var conn = new OleDbConnection("...ConnectionString...");
            var selectCmd = new OleDbCommand(SELECT_CMD, conn);
            selectCmd.Parameters.AddWithValue("p1", "PermissionName");
            selectCmd.Parameters.AddWithValue("p2", 0);
            var adapter = new OleDbDataAdapter(selectCmd);
            var builder = new OleDbCommandBuilder(adapter); //used to generate the UPDATE and DELETE commands...
            adapter.UpdateCommand = builder.GetUpdateCommand(); //etc.
            //Do NOT fill the table here. Instead, let the caller fill it.
            return new LazyDataTable(adapter);
        }
    }
    public string UniqueName { get { return "Permission"; } }
}

您的主程序代码将使用 PermissionSourceLazyDataTable,如下所示:

    static class Program {
    void GetPermissions() {
        ISource permissionSource = SourceManager.Sources.
            Where(s => "Permission".Equals(s.UniqueName)).First();

        var table = permissionSource.Table as LazyDataTable;
        table.SetSelectParam("PermissionName", "Admin");

        //If you want to fill ALL rows in one step:
        table.Fill(); 

        // OR If you want to fill one row at a time, and add it to the table:
        DataRow row;
        while(null != (row = table.ReadRow())) {
            //do something with each individual row. Exit whenever desired.
            Console.WriteLine(row["PermissionName"]);
        }

        // OR If you prefer IEnumerable semantics:
        DataRow row = table.LazyReadRows().FirstOrDefault(someValue.Equals(row["columnname"]));

        //OR use foreach, etc. Rows are still ONLY read one at a time, each time IEnumerator.MoveNext() is called.
        foreach (var row in table.LazyReadRows())
            if (row["someColumn"] == "someValue")
                DoSomething(row["anothercolumn"]);
    }
}

您当然可以混合和匹配此处显示的 LazyDataTable 的各个部分,以在您的应用程序限制范围内实现您想要的。如果您可以切换到不同的共享数据模型当然会好得多,但是如果您必须从每个源返回一个 DataTable,那么至少您可以在必要时返回一个功能更强大的 DataTable正如我在这里演示的那样对其进行子类化。这使您可以传回更多信息,您可以根据需要使用这些信息来填充表格。 我仍然鼓励您查看 LinqToSQL 以及可能尝试切换到简单地传回 DbDataReader 或类似于我在此处显示的 LazyDataTable 的其他一些对象,这将允许您自定义原始查询(例如,通过使用SetSelectParam 方法)以及一次读取一行中的数据。

希望对您有所帮助!

关于c# - 在 C# 中扩展 DataTable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12162235/

有关c# - 在 C# 中扩展 DataTable的更多相关文章

  1. ruby - 使用 C 扩展开发 ruby​​gem 时,如何使用 Rspec 在本地进行测试? - 2

    我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当

  2. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  3. C# 到 Ruby sha1 base64 编码 - 2

    我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha

  4. c - mkmf 在编译 C 扩展时忽略子文件夹中的文件 - 2

    我想这样组织C源代码:+/||___+ext||||___+native_extension||||___+lib||||||___(Sourcefilesarekeptinhere-maycontainsub-folders)||||___native_extension.c||___native_extension.h||___extconf.rb||___+lib||||___(Rubysourcecode)||___Rakefile我无法使此设置与mkmf一起正常工作。native_extension/lib中的文件(包含在native_extension.c中)将被完全忽略。

  5. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  6. ruby-on-rails - 向 Rails 3 添加 Ruby 扩展方法的最佳实践? - 2

    我有一个要在我的Rails3项目中使用的数组扩展方法。它应该住在哪里?我有一个应用程序/类,我最初把它放在(array_extensions.rb)中,在我的config/application.rb中我加载路径:config.autoload_paths+=%W(#{Rails.root}/应用程序/类)。但是,当我转到railsconsole时,未加载扩展。是否有一个预定义的位置可以放置我的Rails3扩展方法?或者,一种预先定义的方式来添加它们?我知道Rails有自己的数组扩展方法。我应该将我的添加到active_support/core_ext/array/conversion

  7. ruby - 如何在 ruby​​ 中复制目录结构,不包括某些文件扩展名 - 2

    我想编写一个ruby​​脚本来递归复制目录结构,但排除某些文件类型。因此,给定以下目录结构:folder1folder2file1.txtfile2.txtfile3.csfile4.htmlfolder2folder3file4.dll我想复制这个结构,但不包含.txt和.cs文件。因此,生成的目录结构应如下所示:folder1folder2file4.htmlfolder2folder3file4.dll 最佳答案 您可以使用查找模块。这是一个代码片段:require"find"ignored_extensions=[".cs"

  8. ruby - 扩展类和实例 - 2

    这个问题有两个部分。在RubyProgrammingLanguage一书中,有一个使用模块扩展字符串对象和类的示例(第8.1.1节)。第一个问题。为什么如果您使用新方法扩展类,然后创建该类的对象/实例,则无法访问该方法?irb(main):001:0>moduleGreeter;defciao;"Ciao!";end;end=>nilirb(main):002:0>String.extend(Greeter)=>Stringirb(main):003:0>String.ciao=>"Ciao!"irb(main):004:0>x="foobar"=>"foobar"irb(main):

  9. ruby - 动态扩展现有方法或覆盖 ruby​​ 中的发送方法 - 2

    假设我们有A、B、C类。Adefself.inherited(sub)#metaprogramminggoeshere#takeclassthathasjustinheritedclassA#andforfooclassesinjectprepare_foo()as#firstlineofmethodthenrunrestofthecodeenddefprepare_foo#=>prepare_foo()neededhere#somecodeendendBprepare_foo()neededhere#somecodeendend如您所见,我正在尝试将foo_prepare()调用注入

  10. c# - C# 中的 Flatten Ruby 方法 - 2

    我如何做Ruby方法"Flatten"RubyMethod在C#中。此方法将锯齿状数组展平为一维数组。例如:s=[1,2,3]#=>[1,2,3]t=[4,5,6,[7,8]]#=>[4,5,6,[7,8]]a=[s,t,9,10]#=>[[1,2,3],[4,5,6,[7,8]],9,10]a.flatten#=>[1,2,3,4,5,6,7,8,9,10 最佳答案 递归解决方案:IEnumerableFlatten(IEnumerablearray){foreach(variteminarray){if(itemisIEnume

随机推荐