Code First DatabaseGenerated Composite主键的问题

时间:2013-10-20 03:20:51

标签: c# entity-framework tsql asp.net-mvc-4 ef-code-first

这有点复杂,拜托,我知道反对自然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

当我尝试创建记录时,这就是我得到的错误:

  

已成功提交对数据库的更改,但更新对象上下文时发生错误。 ObjectContext可能处于不一致状态。内部异常消息:无法更改对象状态。此异常可能是由于一个或多个主键属性设置为null。未添加的对象不能具有空主键值。有关详细信息,请参阅内部异常。

现在,对我来说有趣的是,在我停止调试并重新开始之后,一切都很完美。触发器完全触发,因此复合PK是唯一且完美的,其他列中的数据完好无损。

我的猜测是,EF很容易被这样一个事实搞糊涂,因为在给出插入命令后,PK似乎没有任何价值。此外,似乎支持这一理论,当我尝试编辑行时,在调试中,我收到以下错误:

  

传递的主键值的数量必须与实体上定义的主键值的数量匹配。

如果我尝试拉出“详细信息”或“删除”功能,则会出现相同的错误。

关于如何解决此问题的任何解决方案或想法?我对任何事情都很开放,甚至创建一个隐藏的int PK。但这似乎是多余的。

编辑21OCT13

[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);
    }

编辑21OCT2013最终代码解决方案 对于像我这样的人,他们一直在寻找清晰完整的解决方案。

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");
        }

1 个答案:

答案 0 :(得分:1)

hy你不是通过代码管理而不是使用触发器吗?

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();

这可以解决你的问题。