简体   繁体   中英

Select NULL values from SQL Server table

I am working with ASP.NET MVC 4 using C# and SQL Server

I am selecting a row of data from the following table

CREATE TABLE [dbo].[Mem_Basic] (
[Id]          INT           IDENTITY (1, 1) NOT NULL,
[Mem_NA]      VARCHAR (100) NOT NULL,
[Mem_Occ]     VARCHAR (200) NOT NULL,
[Mem_Role]    VARCHAR (200) NOT NULL,
[Mem_Email]   VARCHAR (50)  NULL,
[Mem_MPh]     VARCHAR (15)  NULL,
[Mem_DOB]     DATE          NULL,
[Mem_BGr]     NCHAR (10)    NULL,
[Mem_WAnn]    DATE          NULL,
[Mem_Spouse]  VARCHAR (75)  NULL,
PRIMARY KEY CLUSTERED ([Id] ASC)
);

using the following code

public MemberBasicData GetMemberProfile(int id)
{
        MemberBasicData mb = new MemberBasicData();
        using (SqlConnection con = new SqlConnection(Config.ConnectionString))
        {
            using (SqlCommand cmd = new SqlCommand("SELECT * FROM Mem_Basic WHERE Id="+id+"", con))
            {
                try
                {
                    con.Open();
                    SqlDataReader reader = cmd.ExecuteReader();
                   if(reader.Read()==true)
                    {
                        mb.Id = (int)reader["Id"];
                        mb.Mem_NA = (string)reader["Mem_NA"];
                        mb.Mem_Occ = (string)reader["Mem_Occ"];
                        mb.Mem_Role = (string)reader["Mem_Role"];
                        mb.Mem_Email = (string)reader["Mem_Email"];
                        mb.Mem_MPh = (string)reader["Mem_MPh"];
                        mb.Mem_DOB = (Convert.ToDateTime(reader["Mem_DOB"]));
                        mb.Mem_BGr = (string)reader["Mem_BGr"];
                        mb.Mem_WAnn = (Convert.ToDateTime(reader["Mem_WAnn"]));
                        mb.Mem_Spouse = (string)reader["Mem_Spouse"];
                   }
                }
                catch (Exception e) { throw e; }
                finally { if (con.State == System.Data.ConnectionState.Open) con.Close(); }
            } 
        }
        return mb;
    }

This shows the error

Unable to cast object of type 'System.DBNull' to type 'System.String'.

( Mem_Email , MPh .. etc sometimes contain a NULL value.. if the value is null I want return null). Anybody please help me.

只要做一些简短的if,你应该为所有其他变量做同样的事情:

 mb.Mem_Email = reader["Mem_Email"] == System.DBNull.Value ? null : (string) reader["Mem_Email"];

You could save yourself a serious amount of pain here with a tool like dapper ( http://www.nuget.org/packages/Dapper ):

public MemberBasicData GetMemberProfile(int id)
{
    using (var con = new SqlConnection(Config.ConnectionString))
    {
        return con.Query<MemberBasicData>(
            "SELECT * FROM Mem_Basic WHERE Id=@id",
            new { id } // full parameterization, done the easy way
        ).FirstOrDefault();
    }
}

things this does:

  • does correct parameterization (for both performance and safety), but without any inconvenience
  • does all the materialization, handling nulls (both in parameters and columns) for you
  • is insanely optimized (basically, it is measurably the same speed as writing all that code yourself, except fewer things to get wrong)

Alternatively to King King's answer you can write code like this:

mb.Mem_Email = reader["Mem_Email"] as string;

For value types, if the column allows nulls, it's a good practice to map them to nullable value types in C# so that this code reader["Mem_DOB"] as DateTime? works

Change for all columns, that might be NULL from this

mb.Mem_NA = (string)reader["Mem_NA"];

to that

mb.Mem_NA = reader["Mem_NA"].ToString();

Treat the nullable fields:

mb.Mem_Email = System.DBNull.Value.Equals(reader["Mem_Email"])?"":
                                      (string)reader["Mem_Email"];

Do the same for: mb.Mem_MPh, mb.Mem_BGr and mb.Mem_Spouse.

I don't mean to sound like a SQL bigot (which of course means I DO mean to sound like a SQL bigot), but if you followed SQL best practices and used a column list instead of SELECT * you could resolve this problem by using COALESCE on the nullable columns thus:

SELECT
  [Id],
  [Mem_NA],
  [Mem_Occ],
  [Mem_Role],
  COALESCE( [Mem_Email], '' ) AS [Mem_Email],
  COALESCE( [Mem_MPh], '' ) AS [Mem_MPh],
  COALESCE( [Mem_DOB], CAST( '1753-1-1' AS DATE ) ) AS [Mem_DOB],
  COALESCE( [Mem_BGr, '' ) AS [Mem_BGr],
  COALESCE( [Mem_WAnn], CAST( '1753-1-1' AS DATE ) ) AS [Mem_WAnn],
  COALESCE( [Mem_Spouse], '' ) AS [Mem_Spouse]
FROM 
  [dbo].[Mem_Basic];

Your c# code can now dependably process the result set without having to account for outliers (the exception being the dates; you should probably check for whatever default you use in the COALESCE for those (I used the minimum allowable value for a SQL Date variable in the above example), and handle them appropriately.

Additionally, you can get rid of the finally block in your c# code. You wrapped the connection in a "using" block; it will automatically close the connection when you go out of scope (that is the purpose of the "using" block).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM