C# 如何使用ASP.NET MVC在数据库中存储多个复选框值

C# 如何使用ASP.NET MVC在数据库中存储多个复选框值,c#,sql-server,asp.net-mvc,stored-procedures,C#,Sql Server,Asp.net Mvc,Stored Procedures,我正在开发一个使用ASP MVC和存储过程(SQL Server)的项目,我想在数据库中存储复选框项。我试图在模型中添加一个列表类型,以便访问这些值,然后将它们存储在数据库中 问题在于,关系数据库是专门为每行/列组合存储一个值而设计的。为了存储多个值,我必须将列表序列化为单个值进行存储,然后在检索时对其进行反序列化 这是我的视图标记: <h6>Items</h6> <ul>

我正在开发一个使用ASP MVC和存储过程(SQL Server)的项目,我想在数据库中存储复选框项。我试图在模型中添加一个
列表
类型,以便访问这些值,然后将它们存储在数据库中

问题在于,关系数据库是专门为每行/列组合存储一个值而设计的。为了存储多个值,我必须将列表序列化为单个值进行存储,然后在检索时对其进行反序列化

这是我的视图标记:

               <h6>Items</h6>
                    <ul>
                        <li>
                            <label class="anim">
                                <input type="checkbox" class="checkbox" value="Soups" name="Items">
                                <span>Soups</span>
                            </label>
                        </li>
                        <li>
                            <label class="anim">
                                <input type="checkbox" class="checkbox" value="Burger" name="Items" >
                                <span>Burger</span>
                            </label>
                        </li>
                        <li>
                            <label class="anim">
                                <input type="checkbox" class="checkbox" value="Drinks" name="Items">
                                <span>Drinks</span>
                            </label>
                        </li>
                        <li>
                            <label class="anim">
                                <input type="checkbox" class="checkbox" value="Desserts" name="Items">
                                <span>Desserts</span>
                            </label>
                        </li>
                    </ul>
型号:

public List<string> Items { get; set; }
公共列表项{get;set;}

您不应该序列化/反序列化。这将是痛苦的使用后

假设您需要检索选中项目1和项目5的对象。 如果它被序列化为一个字符串,那么按如下方式存储它的效率和容易性就会降低

假设您有一个“Person”表,您想查看他们拥有的“Consoles”列表

您将有tableperson

  • id int主键
  • 名称varchar不为空
和控制台

  • id int主键
  • 名称varchar不为空
以及存储控制台所属的表:

自有控制台

  • id int主键
  • person_id int(外键=>person(id))
  • 控制台id int(外键=>控制台(id))
在代码中,您将根据选中的复选框插入一条记录

人:

  • (1) 托马斯
  • (2) 皮埃尔
控制台:

  • (1) NES
  • (2) MegaDrive
  • (3) 新地理
个人电脑控制台:

  • (1) (一)
  • (1) (二)
  • (1) (三)

  • (2) (一)

  • (2) (一)
然后你可以做如下事情:

SELECT * 
FROM   person p
INNER  JOIN owned_console oc
ON     p.id = oc.person_id
WHERE  oc.console_id IN (3,1);
标志枚举-

[Flags]
public enum ItemStorage
{
    Soups = 1,
    Burger = 2,
    Drinks = 4,
    Dessert = 8,
    Cheese = 16
}
我添加奶酪只是为了强调Flags枚举的二进制性质

这是你的另一个密码-

public class Stuff
{
    private List<string> Items;
    private static string Connection()
    {
        return ConfigurationManager.ConnectionStrings["deliverycon"].ToString();
    }

    public bool DoStuff()
    {
        try
        {
            using (SqlConnection con = new SqlConnection(Connection()))
            {
                using (SqlCommand cmd = new SqlCommand("AddNewBestellung", con))
                {

                    cmd.Parameters.AddWithValue("@Items", (int)ConstuctEnumValueFromList(Items));
                    //other saved parameters...

                    con.Open();
                    int i = cmd.ExecuteNonQuery();
                    con.Close();

                    if (i >= 1)
                        return true;
                    else
                        return false;
                }
            }
        }
        catch (Exception ex)
        {
            string e = ex.Message;
            return false;
        }
    }

    private ItemStorage ConstuctEnumValueFromList(List<string> list)
    {
        var result = new ItemStorage();
        if (list.Any())
        {
            var separatedList = string.join(",", list)
            bool success = Enum.TryParse<ItemStorage>(separatedList, out result)
        }
        return result;
    }
}
这应该给你 “汤、汉堡、饮料、甜点”

XML序列化

首先,确保您熟悉。此方法要求将Items集合存储到SQL Server中的XML列中。它还有一个优点,就是您可以查询该列,只要您不怕SQLXML和XPath。许多开发人员都是这样

一旦你有了它,一切看起来都非常相似(如果简单一点的话)

公共类的东西
{
私人清单项目;
私有静态字符串连接()
{
返回ConfigurationManager.ConnectionString[“deliverycon”].ToString();
}
公共图书馆
{
尝试
{
使用(SqlConnection con=newsqlconnection(Connection()))
{
使用(SqlCommand cmd=newsqlcommand(“AddNewBestellung”,con))
{
cmd.Parameters.AddWithValue(“@Items”,ConstructXmlFromList(Items));
//其他保存的参数。。。
con.Open();
int i=cmd.ExecuteNonQuery();
con.Close();
如果(i>=1)
返回true;
其他的
返回false;
}
}
}
捕获(例外情况除外)
{
字符串e=例如消息;
返回false;
}
}
公共静态T FromXML(字符串xml)
{
使用(var stringReader=newstringreader(xml))
{
var serializer=newxmlserializer(typeof(T));
返回(T)序列化程序。反序列化(stringReader);
}
}
公共字符串ToXML(T obj)
{
使用(var stringWriter=new stringWriter(new StringBuilder()))
{
var xmlSerializer=新的xmlSerializer(typeof(T));
Serialize(stringWriter,obj);
返回stringWriter.ToString();
}
}
私有字符串构造函数XmlFromList(列表列表)
{
返回ToXML(列表);
}
}
同样,很容易将XML片段重新水化到您开始使用的
列表中。你只要使用

var myList = FromXML<List<string>>(fieldValue);
var myList=FromXML(fieldValue);

实际上,您可以尝试使用标志枚举,因为您使用的是SQL Server,您还可以将复选框值数组存储为XML。SQL呢datatype@RichBryant谢谢,但你能解释一下吗,我会把这两个选项都做为答案,你可以试试。谢谢,但创建新表很复杂,我只想在一列中存储多个选项,我不同意,这很简单。见其他答案。接下来,我将序列化为XML,这样您就可以看到这是多么容易了。@Exact:这是正确的、关系式的处理方式。永远不要在一个单元格中存储多个值,只要说不就行了!要在单元格中用逗号分隔值,您将看到一场维护噩梦!从一开始就正确地做@Thomas:-在ANSI-92 SQL标准(25年前!)中,用正确的ANSI
JOIN
语法替换了老式的逗号分隔的表列表样式,并且它的使用非常方便discouraged@Exact:存储多个值的正确关系方式是一个单独的表(每个值一行),用于处理“多个值”对于单个实体,谢谢,我必须在model?中编写Flags枚举,或者仅仅是一个整数值。任何一个都可以。好的,我会根据您的建议尝试让您知道,当我检查超过1个值时,只有第一个检查的值存储在数据库中,这很有趣。尝试在ConstructEnumValueFromList(List List)方法中放置断点并单步执行。
int i = 1 + 2 + 4 + 8;
var items = (ItemStorage)i;
Console.WriteLine(items.ToString());
public class Stuff
{
    private List<string> Items;
    private static string Connection()
    {
        return ConfigurationManager.ConnectionStrings["deliverycon"].ToString();
    }

    public bool DoStuff()
    {
        try
        {
            using (SqlConnection con = new SqlConnection(Connection()))
            {
                using (SqlCommand cmd = new SqlCommand("AddNewBestellung", con))
                {

                    cmd.Parameters.AddWithValue("@Items", ConstructXmlFromList(Items));
                    //other saved parameters...

                    con.Open();
                    int i = cmd.ExecuteNonQuery();
                    con.Close();

                    if (i >= 1)
                        return true;
                    else
                        return false;
                }
            }
        }
        catch (Exception ex)
        {
            string e = ex.Message;
            return false;
        }
    }

    public static T FromXML<T>(string xml)
    {
        using (var stringReader = new StringReader(xml))
        {
            var serializer = new XmlSerializer(typeof(T));
            return (T)serializer.Deserialize(stringReader);
        }
    }

    public string ToXML<T>(T obj)
    {
        using (var stringWriter = new StringWriter(new StringBuilder()))
        {
            var xmlSerializer = new XmlSerializer(typeof(T));
            xmlSerializer.Serialize(stringWriter, obj);
            return stringWriter.ToString();
        }
    }

    private string ConstructXmlFromList(List<string> list)
    {
        return ToXML(list);
    }
}
var myList = FromXML<List<string>>(fieldValue);