【问题标题】:Database interaction using C# without Entity Framework使用没有实体框架的 C# 进行数据库交互
【发布时间】:2016-01-23 00:34:34
【问题描述】:

我被分配了一个任务,我需要在其中显示一个表单,该表单的数据位于 Sql server 的各个表中。要求严格不要使用实体框架或存储过程。在这种情况下,我有什么选择?

目前我正在使用 SqlCommand 对象运行一些 sql 查询,但是当涉及到获取关系数据然后允许用户从表单更新它时,事情变得非常复杂。

Winforms 中允许查看和编辑关系数据的最佳方式/方法是什么?

【问题讨论】:

  • 你可以使用Linq2Sql吗?或者你可以和你的老师混在一起使用 NHibernate 或其他 .net ORM 吗?
  • 是的,只需使用 SqlConnection/SqlCommand/SqlDataReader。
  • @NickBailey:如果禁止 EF,则很可能意味着禁止任何 ORM。
  • 您的问题有一个非常简短的答案。那就是 ado.net。你还想知道什么吗?如果是这样,请添加您的代码,就您遇到的问题提出具体问题。
  • @KosalaW 对不起,我误读了你的讽刺。不过,我不同意——教授底层技术(即使在 C# 中)并没有错——人们仍然在教算术,尽管 Siri 可以为你做数学。

标签: c# .net sql-server ado.net


【解决方案1】:

您可以为需要访问/更新的对象编写自己的简单类。 出于以下示例的目的,我们假设您有 2 个表:

人物

  • Person_Id INT PRIMARY KEY NOT NULL
  • 名称 NVARCHAR(100) NULL

电子邮件

  • Person_Id INT PRIMARY KEY NOT NULL
  • Email_Id INT PRIMARY KEY NOT NULL
  • 电子邮件 NVARCHAR(100) 非空

    public class MyProgram
    {
    
        public List<Person> ReadRecords()
        {
            // Set up your connection
            SqlConnection conn = new SqlConnection();
            conn.Open();
    
            SqlCommand cmd = new SqlCommand("SELECT * FROM Person", conn);
            SqlDataReader reader = cmd.ExecuteReader();
    
            List<Person> personRecords = new List<Person>();
    
            while (reader.Read())
            {
                Person p = new Person(reader, conn);
                personRecords.Add(p);
            }
    
            return personRecords;
        }
    
        public int UpdateRecords(IEnumerable<Person> records, SqlConnection conn)
        {
            int personsUpdated = 0;
            int recordsUpdated = 0;
    
            foreach (Person p in records)
            {
                if (p.Changed)
                {
                    recordsUpdated += p.Update(conn);
                    personsUpdated++;
                }
            }
    
            return recordsUpdated;
        }
    }
    
    public class Person
    {
        public const string SqlGetPersonEmailsCommand = "SELECT Email_Id, Email FROM Emails WHERE Person_Id = @Person_Id";
        public const string SqlUpdatePersonCommand = "UPDATE Person SET Name = @Name WHERE Id = @OriginalId";
        public const string SqlUpdatePersonEmailCommand = "UPDATE Emails SET Email = @Email WHERE Email_Id = @Email_Id";
    
        public int OriginalId { get; private set; }
    
        private bool personChanged;
        private bool emailsChanged { get { return changedEmails.Count > 0; } }
        public bool Changed { get { return personChanged || emailsChanged; } }
    
        private int _id;
        public int Id
        {
            get { return _id; }
            set
            {
                throw new Exception("Changing Id is not allowed.");
            }
        }
    
        private string _name;
    
        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                personChanged = true;
            }
        }
    
        private List<int> changedEmails;
        private Dictionary<int, string> _emailAddresses;
        public string[] EmailAddresses
        {
            get
            {
                string[] values = new string[_emailAddresses.Count];
                _emailAddresses.Values.CopyTo(values, 0);
                return values;
            }
        }
    
        public void UpdateEmail(int emailId, string newEmail)
        {
            _emailAddresses[emailId] = newEmail;
            changedEmails.Add(emailId);
        }
    
        public Person(IDataReader reader, SqlConnection conn)
        {
            // Read ID (primary key from column 0)
            OriginalId = _id = reader.GetInt32(0);
    
            // Check if value in column 1 is Null; if so, set _name to Null, otherwise read the value
            _name = reader.IsDBNull(1) ? null : reader.GetString(1);
    
            // Now get all emails for this Person record
            SqlCommand readEmailsCmd = new SqlCommand(SqlGetPersonEmailsCommand, conn);
            readEmailsCmd.Parameters.Add("@Person_Id", SqlDbType.Int);
            readEmailsCmd.Parameters["@Person_Id"].Value = OriginalId;
    
            SqlDataReader emailReader = readEmailsCmd.ExecuteReader();
    
            changedEmails = new List<int>();
            _emailAddresses = new Dictionary<int, string>();
    
            if (emailReader.HasRows)
            {
                while (emailReader.Read())
                {
                    int emailId = emailReader.GetInt32(0);
                    string email = emailReader.GetString(1);
    
                    _emailAddresses.Add(emailId, email);
                }
            }
        }
    
    
        public int Update(SqlConnection conn)
        {
            int rowsUpdated = 0;
    
            SqlCommand command = null;
    
            // Update Person record
            if (personChanged)
            {
                command = new SqlCommand(SqlUpdatePersonCommand, conn);
    
                command.Parameters.Add("@OriginalId", SqlDbType.Int);
                command.Parameters["@OriginalId"].Value = OriginalId;
    
                command.Parameters.Add("@Name", SqlDbType.NVarChar);
                command.Parameters["@Name"].Value = _name;
    
                rowsUpdated = command.ExecuteNonQuery();
            }
    
            // Now update all related Email records
            foreach (int id in changedEmails)
            {
                command = new SqlCommand(SqlUpdatePersonEmailCommand, conn);
    
                command.Parameters.Add("@Email_Id", SqlDbType.Int);
                command.Parameters["@Email_Id"].Value = id;
    
                command.Parameters.Add("@Email", SqlDbType.NVarChar);
                command.Parameters["@Email"].Value = _emailAddresses[id];
    
                rowsUpdated = +command.ExecuteNonQuery();
            }
    
            return rowsUpdated;
        }
    }
    

以上示例支持更改人员的姓名和关联的电子邮件地址。

【讨论】:

    【解决方案2】:

    在这种情况下,我认为最好的方法是使用Dapper。您将非常接近 ADO.NET 并控制所有 SQL 查询。同时,您不会花时间在映射功能上——因为这是非常简单但耗时的代码部分。

    【讨论】:

      【解决方案3】:
      • 问题 #1 以“[除了实体框架]我有哪些选择?”结尾。并且您在 cmets(直接 ADO.NET 或 NHibernate)中得到了答案。您也知道这一点,因为您说您使用的是 SqlCommand。

      • 第 2 个问题比较难,我认为这是您的讲师希望您找出的问题:“Winforms 中允许查看和编辑关系数据的最佳方式/方法是什么?”

      我使用 Microsoft Stack 为关系数据制作了大量 UI。但不管技术如何,你都需要一个好的模式或方法。简短的回答(那不是一本书)是从 UI 中抽象出数据。这样他们就可以独立工作,也可以独立改变。

      首先实现编辑数据和显示数据应该是你程序的两个不同部分。我喜欢的一种方法是从 SQL SERVER 中选择您的关系数据作为 XML,然后使用 XSLT 来显示它:

      <Customer>
          <Name>...
          <Company>...
          <Phone>...
          <BillingAddresses>
               <Address>...
               <Address>...
          <PayementMethods>
               <CreditCard>...
               <CreditCard>...
          <RecentOrders>
               <Order>...
               <Order>...
               <Order>...
      

      您可以使用 XSLT 轻松地将其转换为看起来像您想要的任何内容的 HTML。在此示例中,在您显示每个 &lt;Address&gt;&lt;CreditCard&gt; 的位置旁边,您可以放置​​ EDIT/DELETE 链接以及每个部分下的 ADD 链接。

      单击 EDIT/DELETE/ADD 将带您进入一个屏幕以修改该部分关系数据。当您返回将 XML 显示为 HTML 的屏幕时,您会看到更新后的数据。

      这很好,因为您无需重新编译代码即可轻松修改 XML。您还可以使用 XSLT 以您想要的任何布局显示数据。然后,您的 XML 可以包含存储为代码的文字(AMX=AMERICAN EXPRESS 等)。

      任何人,这只是一种没有实际要求的解决方案(例如支持“UNDO”、一次应用多个更改等)。

      【讨论】:

      • 谢谢,但这里主要关注 C# 和 SQL。使用 XML 可能会提供可行的解决方案,但这不是他所追求的。不允许使用 NHibernate 等第三方工具。
      【解决方案4】:

      ADO.NET 是数据库访问的最佳选择。这是 EF 所基于的技术。要显示数据,您大部分时间都使用数据绑定。为了保存和检索数据,您使用 ADO.NET。您可能不想将 ADO 对象直接绑定到 UI,而是使用视图模型。但传统上和文档中的 ASP.NET 数据集通常直接绑定到 UI,从今天看来,这是一种糟糕的编程风格。

      【讨论】:

        【解决方案5】:

        创建数据集将是最佳选择。 使用数据集的步骤 1. 右键单击​​您的项目,Go Add => New Item => Dataset。即.xsd 格式文件。 2. 在该文件中右键单击数据集内,再次添加 => 表适配器。从那之后,您需要完成您的数据连接,然后选择您的表,开始编写您的查询。 3. 创建完成后,您可以直接将查询连接到类文件。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-09-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多