代码优先数据库生成的复合主键出现问题
本文关键字:问题 复合 数据库 代码 | 更新日期: 2023-09-27 18:36:08
这有点复杂,拜托,我知道所有反对自然PK的论点,所以我们不需要讨论。
使用 VS2012/MVC4/C#/CodeFirst
因此,PK基于日期和相应的数字。因此,今天创建的几行将是这样的:
20131019 1
20131019 2
明天创建一个:
20131020 1
这必须使用 C# 自动生成,或者作为触发器或其他方式生成。用户不会输入此内容。我确实想出了一个解决方案,但我遇到了问题,我有点卡住了,因此提出了这个问题。
所以,我有一个模型:
public class MainOne
{
//[Key]
//public int ID { get; set; }
[Key][Column(Order=1)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string DocketDate { get; set; }
[Key][Column(Order=2)]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public string DocketNumber { get; set; }
[StringLength(3, ErrorMessage = "Corp Code must be three letters")]
public string CorpCode { get; set; }
[StringLength(4, ErrorMessage = "Corp Code must be four letters")]
public string DocketStatus { get; set; }
}
完成模型后,我使用 VS2012 基架创建新的控制器和视图。
然后,我正在做的是调试以创建数据库,然后在 Code First 创建数据库后添加以下内容而不是触发器 [我不知道这是否正确过程]:
CREATE TRIGGER AutoIncrement_Trigger ON [dbo].[MainOnes]
instead OF INSERT AS
BEGIN
DECLARE @number INT
SELECT @number=COUNT(*) FROM [dbo].[MainOnes] WHERE [DocketDate] = CONVERT(DATE, GETDATE())
INSERT INTO [dbo].[MainOnes] (DocketDate,DocketNumber,CorpCode,DocketStatus) SELECT (CONVERT(DATE, GETDATE
())),(@number+1),inserted.CorpCode,inserted.DocketStatus FROM inserted
END
当我尝试创建记录时,这是我收到的错误:
已成功提交对数据库的更改,但在更新对象上下文时出错。对象上下文可能处于不一致的状态。内部异常消息:无法更改对象状态。此异常可能是由于一个或多个主键属性设置为 null。未添加的对象不能具有空主键值。 有关详细信息,请参阅内部异常。
现在,对我来说有趣的是,在我停止调试并重新开始之后,一切都很完美。触发器完美触发,因此复合PK是唯一且完美的,其他列中的数据完好无损。
我的猜测是,EF 对这样一个事实感到困惑,即在给出插入命令之后,PK 似乎没有价值。另外,似乎支持这一理论的是,当我尝试在调试中编辑行时,我收到以下错误:
传递的主键值数必须与实体上定义的主键值数匹配。
如果我尝试拉取"详细信息"或"删除"功能,也会发生同样的错误。
关于如何实现这一目标的任何解决方案或想法?我对任何事情都非常开放,甚至创建一个隐藏的int PK。但这似乎是多余的。
编辑13年10月21日
[HttpPost]
public ActionResult Create(MainOne mainone)
{
if (ModelState.IsValid)
{
var countId = db.MainOnes.Count(d => d.DocketDate == mainone.DocketNumber); //assuming that the date field already has a value
mainone.DocketNumber = countId + 1; //Cannot implicitly convert type int to string
db.MainOnes.Add(mainone);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(mainone);
}
编辑 2013 年 10 月 21 日最终代码解决方案对于像我这样不断寻找清晰完整的解决方案的人。
if (ModelState.IsValid)
{
String udate = DateTime.UtcNow.ToString("yyyy-MM-dd");
mainone.DocketDate = udate;
var ddate = db.MainOnes.Count(d => d.DocketDate == mainone.DocketDate); //assuming that the date field already has a value
mainone.DocketNumber = ddate + 1;
db.MainOnes.Add(mainone);
db.SaveChanges();
return RedirectToAction("Index");
}
你不是通过代码而不是使用触发器来管理它吗?
var countId = context.MainOne.Count(d => d.DocketDate == newItem.DocketNumber); //assuming that the date field already has a value
newItem.DocketNumber = CountId + 1;
Context.MainOne.Add(newItem);
context.SaveChanges();
这应该可以解决您的问题。