更有效的方式来访问多个数据库列

时间:2012-05-03 14:29:39

标签: c# database linq-to-sql c#-4.0 nullable

我正在寻找一种更有效的方法来构建多个数据库列的分号分隔列表。我现在使用的代码看起来像这样(并且它可以工作):

//Process List of things
var things = DB.DbColumn_1.HasValue ? DB.DbColumn_1.Value.Equals(true) ? "thing 1;" : "" : "");
things += DB.DbColumn_2.HasValue ? DB.DbColumn_2.Value.Equals(true) ? "thing 2;" : "" : "");
things += DB.DbColumn_3.HasValue ? DB.DbColumn_3.Value.Equals(true) ? "thing 3;" : "" : "");
things += DB.DbColumn_4.HasValue ? DB.DbColumn_4.Value.Equals(true) ? "thing 4;" : "" : "");
// Remove final ';' from thing list if non-empty
things = things.Length > 0 ? things.Substring(0, things.Length-1) : things;

我实际上有大约8个要处理的列 - 这个例子让你有一些不足。所以我有一个很难看的代码块来构建一个简单的字符串。虽然这似乎工作得很好,但对于我正在尝试做的事情来说似乎有太多代码。另外,在这种情况下,我应该警惕使用“.Equals()”吗?

在一些头脑风暴之后,我想出了一些似乎没有比这更有效的东西,比如构建一个单独的函数来创建字符串本身。所有列都是唯一可空的bool,并且所有列都具有唯一的字符串输出。

或者我是否有效地访问这些元素而不用担心它?

谢谢!

3 个答案:

答案 0 :(得分:2)

DB.DbColumn_1.HasValue && DB.DbColumn_1.Value.Equals(true)是编写DB.DbColumn_1.GetValueOrDefault()的一种非常困难的方式,但它们在功能上是等价的。在http://msdn.microsoft.com/en-us/library/1t3y8s4s(v=vs.80).aspxhttp://msdn.microsoft.com/en-us/library/b3h38hb0.aspx Nullable<T>结构的更多信息(bool?相当于Nullable<bool>,这是您的数据库列的类型) >

您可以使用以下方法之一:

var sections = new List<string>();
if (DB.DbColumn_1.GetValueOrDefault()) sections.Add("thing 1");
if (DB.DbColumn_2.GetValueOrDefault()) sections.Add("thing 2");
//...other columns
var things = string.Join(";", sections);

或者:

var pairs = new List<Tuple<bool?, string>>
{
    Tuple.Create(DB.DbColumn_1, "thing 1"),
    Tuple.Create(DB.DbColumn_2, "thing 2")
    //...other columns
};
var things = string.Join(";", pairs.Where(x => x.Item1.GetValueOrDefault()).Select(x => x.Item2));

或只设置一次pairs

static readonly List<Tuple<Func<DBType, bool?>, string>> pairs = new List<Tuple<Func<DBType, bool?>, string>>
    {
        new Tuple<Func<DBType, bool?>, string>(d => d.DbColumn_1, "thing 1"),
        new Tuple<Func<DBType, bool?>, string>(d => d.DbColumn_2, "thing 2")
        //...other columns
    };

void inSomeMethod()
{
    var things = string.Join(";", pairs.Where(x => x.Item1(DB).GetValueOrDefault()).Select(x => x.Item2));
}

当然,这取决于具体情况,但我最喜欢最后一个。如果pairs声明的详细程度困扰您(即重复Tuple<Func<DBType, bool?>, string>),您可以这样做:

class ReadDbBools : Tuple<Func<DBType, bool?>, string>
{
    public ReadDbBools(Func<DBType, bool?> retrieveFunc, string ifTrue) : base(retrieveFunc, ifTrue) { }
}

static readonly List<ReadDbBools> pairs = new List<ReadDbBools>
{
    new ReadDbBools(d => d.DbColumn_1, "thing 1"),
    new ReadDbBools(d => d.DbColumn_2, "thing 2")
    //...other columns
};

答案 1 :(得分:0)

你可以稍微扩展你的linq-to-sql模型以返回你期望的值,所以你得到了那个部分:

public partial class Entity {
    public string DbColumn_1_Display {
        return (DbColumn_1 ?? false) ? "thing_1" : "";
    }
    /*for each property*/
}

然后选择它你可以这样做:

var result = from db in DB
             select new { 
                   c1 = DbColumn_1_Display,  
                   c2 = DbColumn_2_Display /*etc*/};
var string = string.Format("{0};{1};{2}/*...*/", result.c1, result.c2 /*...*/);

不知道这是否会让事情变得更容易。

答案 2 :(得分:0)

从可以为空的类型开始,覆盖Equals方法,而不是这个

DB.DbColumn_1.HasValue ? DB.DbColumn_1.Value.Equals(true) ? "thing 1;" : "" : ""

你可以写这个

DB.DbColumn_1.Equals(true) ? "thing1;" : ""

同样使用string.Join是一种更简洁的方式来处理末尾的额外分号,这样就可以了:

var things = string.Join(";", new []
    {
        DB.DbColumn_1.Equals(true) ? "thing1" : null,
        DB.DbColumn_2.Equals(true) ? "thing2" : null,
        // etc...
    }.Where(i => i != null));

这使得代码更具可读性,但是对于提高性能并不会有太大帮助,因为无论如何这个处理应该已经非常快了。