【问题标题】:Simplifying creating array column with Linq to SQL使用 Linq to SQL 简化创建数组列
【发布时间】:2013-04-07 08:51:21
【问题描述】:

我需要用未知大小的字符串、整数或其他数组创建 SQL 表。最好的方法是为它创建单独的表。像这样(伪代码如下,我不知道我是否正确使用了“主键”):

public class DataBase : DataContext
{
    public Table<UserAccount> users { get { return GetTable<UserAccount>(); } }
    public Table<UserAccount_roles> userroles { get { return GetTable<UserAccount_roles>(); } }
}

[Table]
public class UserAccount
{
    [Column(IsPrimaryKey = true)]
    public string username;
    [Column]
    public string password;
}

[Table]
public class UserAccount_roles
{
    [Column(IsPrimaryKey = true)]
    public string userName;
    [Column(IsPrimaryKey = true, IsDbGenerated = true)]
    public int roleIdx;
    [Column]
    public int arrayValue;
}

但是,这感觉很笨拙,因为如果我不应该担心 SQL 实现的话,UserAccount_roles 可能只是 UserAccount-class 中的简单“列表角色”。

我宁愿做这样的事情:

public class DataBase : DataContext
{
    public Table<UserAccount> users { get { return GetTable<UserAccount>(); } }
}

[Table]
public class UserAccount
{
    [Column(IsPrimaryKey = true)]
    public string username;
    [Column]
    public string password;
    [MyColumn]
    public MySQLList<DataBase, int> roles;
}

我想过做“class MySQLList&lt;B, T&gt; : List&lt;T&gt;”。在数据库类(“B”)中,我做了一些静态方法来授予对正确数据库的访问权限。然后在 MySQLList 中,我通过重载 List -方法来操作数据库。这应该会导致“在后台”构建和访问表 UserAccount_roles,因为程序员(主要是我)在自定义 List 上看到的只是简化的解决方案。

我的实际问题是:

  1. 我敢打赌,有一些现成的实现。我可以在哪里 找到一个?
  2. 我认为我无法执行任何“[table] class MyTable” - MySQLList 中的声明。我是否必须在那里进行实际的 SQL 语言编码,或者是否有任何方法可以创建 Linq to SQL -class 和 编译/运行时的属性?
  3. 这种方法有什么一般性的注意事项吗?-)

【问题讨论】:

    标签: c# sql arrays linq linq-to-sql


    【解决方案1】:

    如果您想避免显式声明联结表,Entity Framework 可能更适合您。它将允许您直接创建多对多关系,而无需中间类型。

    进一步阅读


    推荐的方法是在 Linq-To-SQL 中创建两个具有多对多关系的表:

    [Table]
    public class UserAccount
    {
        [Column(IsPrimaryKey = true)]
        public string username;
        [Column]
        public string password;
    
        private EntitySet<UserRole> _userRole;
    
        [Association(Storage = "_userRole", OtherKey = "userName")]
        public EntitySet<UserRole> UserRoles
        {
            get { return this._userRole; }
            set { this._userRole.Assign(value); }
        }
    }
    
    [Table]
    public class Role
    {
        [Column(IsPrimaryKey = true)]
        public int roleId;
        [Column]
        public string roleName;
    
        private EntitySet<UserRole> _userRole;
    
        [Association(Storage = "_userRole", OtherKey = "roleId")]
        public EntitySet<UserRole> UserRoles
        {
            get { return this._userRole; }
            set { this._userRole.Assign(value); }
        }
    }
    
    [Table]
    public class UserRole
    {
        [Column(IsPrimaryKey = true)]
        public int roleId;
        [Column(IsPrimaryKey = true)]
        public string userName;
    
        private EntityRef<Role> _role;
    
        [Association(Storage = "_role", ThisKey = "userName")]
        public EntitySet<Role> Role
        {
            get { return this._role.Entity; }
            set { this._role.Assign(value); }
        }
    
        private EntityRef<UserAccount> _userAccount;
    
        [Association(Storage = "_userAccount", ThisKey = "userName")]
        public EntitySet<UserRole> UserAccount
        {
            get { return this._userAccount.Entity; }
            set { this._userAccount.Assign(value); }
        }
    }
    

    优于必须在 C# 中解析和处理的序列化整数数组。您可以轻松地执行以下操作:

    var userRoleIds = myUser.UserRoles.Select(ur => ur.roleId);
    

    但您还可以做更多使用序列化数组无法做到的事情。

    进一步阅读


    如果你真的想在单列中存储一个数组,恐怕在 Linq-to-SQL 中没有标准的方法来做到这一点(可能一些第三方提供商会支持它)。最好的办法是自己进行序列化,如下所示:

    [Table]
    public class UserAccount
    {
        ...
        [Column]
        private string rawRoles;
    
        public IEnumerable<int> Roles
        {
            get 
            {
                return (this.rawRoles == null) 
                    ? return new int[0] : 
                    : this.rawRoles.Split(",").Select(s => int.Parse(s));
            }
            set 
            {
                this.rawRoles = (value == null)
                    ? null
                    : String.Join(",", value);
            }
        }
    }
    

    当然,还有更好的方法来序列化您的数据,这只是一个示例。您不能在任何 Linq-to-SQL 查询中使用它,而且它的数据库设计很差 - 但是,至少它满足您的要求。

    【讨论】:

    • 使用 EntitySet 和 EntityRef 是一个很好的建议,我接受了。但是,我的主要问题是避免每次我想为我的表创建一个单向数据的简单列表时都必须定义一两个额外的表。我如何处理数据本身无关紧要。我目前对如何创建将 Role 和 UserRole -classes 隐藏为不必要信息的通用解决方案更感兴趣。我知道它们只是存储 X 数组的方法,我想在后台自动生成它们。
    • @user2254053 为什么要避免创建表?表正是您的数据库的用途。推荐的解决方案更加灵活、稳定和可靠——它只是很好的数据库设计(当然,可能有少数情况需要这样做,但这种情况很少见)。但是,为了完整起见,我提供了一个替代解决方案。
    • 我不想避免创建表。正好相反。我只是想稍微简化一下,以避免每次需要数据数组时都复制粘贴。当然,通过隐藏表来增加代码的可读性,表的唯一目的是在其他表中表示值数组。字符串解析可以做到这一点,但就像你说的那样,这是一个可怕且限制性的解决方案。
    • @user2254053 我明白了。好吧,Linq-to-SQL 在简洁方面并不是最好的。 AFAIK 你有点被这个样板代码困住了。如果您正在设计一个供其他人使用的 DAL,并且您希望保持 API 干净,您可以创建类型 internal 并提供包装器属性/扩展方法来访问您想要的信息类型。实体框架使您能够直接指定多对多关系而无需显式指定联结表,并且 EF 5 支持枚举,如果您有一组需要表示的固定值会更好。
    • Entity Framework 似乎与我的问题 1 非常匹配。现在我对这两个问题都做了一些研究,这似乎也是 Linq-to-SQL 最明智的解决方案。你想相应地改变你的答案,以便我可以“喜欢”它,还是我应该自己回答?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-31
    • 2010-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-10
    相关资源
    最近更新 更多