C#里使用DataTable进行load时由于查询语句有left join 引起主键为null报异常

老紫竹 2009-09-01 03:02:46
错误很常见:未能启用约束。一行或多行中包含违反非空、唯一或外键约束的值。

表结构是一个主表和一个从表
CREATE TABLE `student` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(20) NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;

insert into student values('张三');

CREATE TABLE `stufav` (
`studentId` int(11) NOT NULL,
`favoriteId` int(11) NOT NULL,
PRIMARY KEY (`studentId`,`favoriteId`)
) DEFAULT CHARSET=utf8;


C#代码为
     private static void TestDataTableLoadNull()
{
using (GBaseConnection conn = new GBaseConnection(connectionString))
{
try
{
conn.Open();
GBaseCommand cmd = conn.CreateCommand();
cmd.CommandText = "select * from student s left join stufav sf on sf.studentId=s.id";
// cmd.ExecuteQuery();
GBaseDataReader reader = cmd.ExecuteReader();
DataTable dt = new DataTable();

dt.Load(reader);
}
catch (Exception ex)
{
throw (ex);
}
finally
{
conn.Close();
}
}
}

因为在第二个表里没有数据,所以left join 的结果集里,最后2个字段为null
而这2个字段又是主键,不能为空,导致在load时出现如下异常:

{"未能启用约束。一行或多行中包含违反非空、唯一或外键约束的值。"}


注意:那个select * 是无法修改的,而且还有其它的情况,就算把*替换为字段名也没用
比如主表一个主键,而从表是多主键,而且后面的操作必须用到这些字段,就算是null
...全文
531 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
zhoujianlong 2011-12-01
  • 打赏
  • 举报
回复
将left join 改为 inner join 应该就没问题了吧【未测试过】
zhoujianlong 2011-12-01
  • 打赏
  • 举报
回复
第一张表[暂定未A表 ]主键Id,第二张表[暂定为B表]主键studentId 和 favoriteId;且 left join ,按定义,主键应是A表中的Id,但实际当B表中有记录且2条(包括两条)以上时,此时之前假设(Id是主键)不成立,若假设studentId和favoriteId是主键,B表中又可能无记录,因此无明确的主键,导致报错,个人理解
claymore1114 2009-09-09
  • 打赏
  • 举报
回复
看看
老紫竹 2009-09-02
  • 打赏
  • 举报
回复

1 sql执行没问题
2 sql语句无法改写,而且就算写上了字段,还是可能因为其它原因造成某些主键为null
3 在vs2005下有异常,一同事的2008下竟然没问题
wh_wangjun 2009-09-01
  • 打赏
  • 举报
回复
sql语句在这二个表上执行,无错误。
gsz_stylm 2009-09-01
  • 打赏
  • 举报
回复
我的想法是既然不能为null,那就设置一个无关的初始值,这样的话应该是不会影响到程序吧。也有一种想法就是手动的生成dataset ,只不过这种方法有点笨,很费劲。
angel6709 2009-09-01
  • 打赏
  • 举报
回复
不对,我这里本来就行的?????
conn.Open();
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "select * from User_Table s left join Table_Input sf on sf.id=s.id";
//cmd.CommandType= CommandType.TableDirect;
DbDataReader reader = cmd.ExecuteReader();
DataTable dt = new DataTable();
//DataSet ds = new DataSet();
//ds.Tables.Add(dt);
//ds.Load(reader, LoadOption.OverwriteChanges, dt);
dt.Load(reader);
dt.Load(reader);

ncjcz 2009-09-01
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 ncjcz 的回复:]
用isnull先给个临时值
不知道能不能满足业务需求
[/Quote]
select s.* ,isnull(sf.studentId,-1) studentId,isnull(sf.favoriteId,-1) favoriteId from student s left join stufav sf on sf.studentId=s.id
在处理逻辑里去处理-1
angel6709 2009-09-01
  • 打赏
  • 举报
回复
 
conn.Open();
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "select * from User_Table as s, Table_Input as sf Where sf.id=s.id";
//cmd.CommandType= CommandType.TableDirect;
DbDataReader reader = cmd.ExecuteReader();
DataTable dt = new DataTable();
DataSet ds = new DataSet();
ds.Tables.Add(dt);
ds.Load(reader, LoadOption.OverwriteChanges, dt);
dt.Load(reader);


试一下,我这里可以的。SqlServer
可能DataAdapter更好
ncjcz 2009-09-01
  • 打赏
  • 举报
回复
用isnull先给个临时值
不知道能不能满足业务需求
qldsrx 2009-09-01
  • 打赏
  • 举报
回复
谁说“那个select * 是无法修改的”的,你有没有写过T-SQL啊,“select *”是很不规范的写法,如果你两种关联的表含有相同列名,那个"*"就会取出重复列,这样会出问题的,必须修改并给别名。

所以你那个只要写成cmd.CommandText = "select id,name,favoriteId from student s left join stufav sf on sf.studentId=s.id";就可以了。
muyebo 2009-09-01
  • 打赏
  • 举报
回复
直接到数据库里运行这个语句行不行,还不行的话就到把帖子转到对应数据库的版块去看看
阿非 2009-09-01
  • 打赏
  • 举报
回复
机器没装 mysql , sql server 下 没问题
阿非 2009-09-01
  • 打赏
  • 举报
回复
用 DataAdapter
然后 填充 DataTable
WOAINI_XF840728 2009-09-01
  • 打赏
  • 举报
回复
第二张表中studentId 一定得有
不然不能使用on sf.studentId=s.id
老紫竹 2009-09-01
  • 打赏
  • 举报
回复
10万火急....
angel6709 2009-09-01
  • 打赏
  • 举报
回复
仔猪大哥怎么到C#了呵呵,

111,129

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Creator Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧