在Entity Framework中使用可空的唯一键

时间:2016-06-02 11:37:35

标签: c# entity-framework

我正在使用.net版本4.5.2和Oracle DB开发一个C#应用程序。

我遇到的问题是我无法将Entity Framework配置为数据库。该数据库包含4列以上的唯一键,但其中2列可以为空。

[Key, Column("GEBRUIKER", Order = 0)]
public string User { get; set; }

[Key, Column("EL1", Order = 1)]
public string Element1 { get; set; }

[Key, Column("EL2", Order = 2)]
public short? Element2 { get; set; }

[Key, Column("EL3", Order = 3)]
public short? Element3 { get; set; }

当我尝试通过数据库中的代码获取值时,我得到一个空引用异常,因为元素2或3是空的。

当我从元素2和3中删除键时,我不会得到正确的数据,因为当元素1在2行时相同时,第二行将缓存元素2和3。

问题:如何处理这些可以为空的唯一键?

添加了额外信息:

嗯,这是数据库创建脚本的一部分:

CREATE TABLE USERS
(
  GEBRUIKER            VARCHAR2(3 BYTE)     NOT NULL,
  EL1                  VARCHAR2(6 BYTE)     NOT NULL,
  EL2                  NUMBER,
  EL3                  NUMBER
)

CREATE UNIQUE INDEX USERS_UK ON USERS
(GEBRUIKER, EL1, EL2, EL3)


ALTER TABLE USERS ADD (
  CONSTRAINT USERS_UK
  UNIQUE (GEBRUIKER, EL1, EL2, EL3)
  USING INDEX USERS_UK
  ENABLE VALIDATE);

无法对结构或数据进行任何更改,因为有多个应用程序使用此数据库。此外,已有EL2和EL3行的值为0.

示例数据:

{'USER1','A','A','C'}
{'USER1','A','B','B'}
{'USER1','B','A','C'}

当我执行linq查询以选择USER1 AND EL1 = A时,我将得到下一个结果:

{'USER1','A','A','C'}
{'USER1','A','A','C'}

而不是:

{'USER1','A','A','C'} 
{'USER1','A','B','B'}

1 个答案:

答案 0 :(得分:1)

不,你不能这样做:

查看表创建SQL:

CREATE TABLE [dbo].[Users](
    [GEBRUIKER] [nvarchar](128) NOT NULL,
    [EL1] [nvarchar](128) NOT NULL,
    [EL2] [smallint] NOT NULL,
    [EL3] [smallint] NOT NULL,
 CONSTRAINT [PK_dbo.Users] PRIMARY KEY CLUSTERED 
(
    [GEBRUIKER] ASC,
    [EL1] ASC,
    [EL2] ASC,
    [EL3] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

所有主键都是非空 !!!!

假设您想要破解此密钥并使用SQL自行更改它,然后您必须发送以下脚本,这将把密钥从nun nullable更改为nullabe!

  usersDatabaseContext.Database.ExecuteSqlCommand(@"
        while(exists(select 1 from INFORMATION_SCHEMA.TABLE_CONSTRAINTS where CONSTRAINT_TYPE='FOREIGN KEY')) 
        begin 
            declare @sql nvarchar(2000) 
            SELECT TOP 1 @sql=('ALTER TABLE ' + TABLE_SCHEMA + '.[TableName]  DROP CONSTRAINT [' + CONSTRAINT_NAME + ']') 
            FROM information_schema.table_constraints 
            WHERE CONSTRAINT_TYPE = 'FOREIGN KEY' 
            exec (@sql) 
        end 

        ALTER TABLE Users DROP CONSTRAINT [PK_dbo.Users]

        ALTER TABLE Users ALTER COLUMN EL2 SMALLINT NULL 
        ALTER TABLE Users 
        ADD CONSTRAINT [PK_dbo.Users] PRIMARY KEY CLUSTERED ( [GEBRUIKER] ASC, [EL1] ASC, [EL2] ASC, [EL3] ASC )", 
        TransactionalBehavior.DoNotEnsureTransaction);

        var user1 = new User { UserName = "Bassam", Element1 = "1", Element2 = null, Element3 = 3 };

我有:

- Removed all foreign keys which are related to this table 
- Dropped the primary key
- Changed the **Column E2 to nullable**
- Adding the modified primary key again

如果是SQL Server,这将导致SQL Server / Oracle DB中出现以下错误: 无法在“用户”表中的可为空的列上定义PRIMARY KEY约束。

要好好考虑一下,即使你说你可以用你的主键做到这一点:

您如何保证PRIMARY密钥的唯一性?假设您的用户实体将创建以下行:

Id1    Id2  Id3  , Id4

"a" , "a" , null , null

您无法再次创建相同的条目,因为该行将存在于表中!