Это немного сложно, и, пожалуйста, я знаю все аргументы против естественных ПК, поэтому нам не нужно это обсуждать.

С использованием 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
Nick Fleetwood 20 Окт 2013 в 07:20

1 ответ

Лучший ответ

Почему вы не управляете этим с помощью кода, а не с помощью триггера?

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

И это должно решить вашу проблему.

1
Raphael 21 Окт 2013 в 10:06
Это действительно то, что я искал. Спасибо! НО, у меня все еще возникают проблемы с этим. Я не уверен, куда поместить этот фрагмент. Я отредактировал вопрос и добавил часть кода контроллера. Для mainone.DocketNumber = countID + 1; "невозможно неявно преобразовать тип int в строку"
 – 
Nick Fleetwood
22 Окт 2013 в 06:51
OK! Я хотел удостовериться, что вы получили правильную причину с парой поправок! 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"); } И мы закончили. Спасибо, сэр!
 – 
Nick Fleetwood
22 Окт 2013 в 07:47