如何在SaveChanges之前创建多个实体? [英] How can I create multiple entities before the SaveChanges?

查看:185
本文介绍了如何在SaveChanges之前创建多个实体?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个质量跟踪网络应用,需要每个解决步骤都由用户签名。为了简化流程,我围绕每个步骤结束时填写日期的人建立了模型。

I have a quality tracking webapp where I need each resolution steps to be signed by a user. To ease the process, I've built my model around following who filled the date at the end of each step.

我简化的失败模型看起来像这样:

My simplified Failure model looks like this:

public class failure {
    [key]
    public string FailureId { get; set; }
    ...
    public int? OpenUserId { get; set; }
    public int? DiagUserId { get; set; }
    public int? CloseUserId { get; set; }
    ...
    [ForeignKey("OpenUserId")]
    public virtual signature OpenUser { get; set; }
    [ForeignKey("DiagUserId")]
    public virtual signature DiagUser { get; set; }
    [ForeignKey("CloseUserId")]
    public virtual signature CloseUser { get; set; }
}

和我的 Signature 模型:

public class signature {
    [key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int SignatureId { get; set; }
    public string UserName { get; set; }
    [Column(TypeName:="Date")]
    [DataType(DataType.Date)]
    public date DateSign { get; set; }
}

此模型的目标是最大程度地减少表中的签名数量。因此,如果用户在一天内多次失败,则代码只需要创建一个签名并重复使用相同的ID。

The goal of this model is to minimize the number of signature in the table. So, if a user signs on multiple failure in one day, the code should only need to create one signature and reuse the same Id.

问题发生在用户填写一次保存多个步骤。创建两个或多个签名(本身可能是一个问题,但现在不是焦点),并且引发错误

The problem arises when a user fills multiple steps in one save. Two or more signatures are created (which can be a problem in itself but it's not the focus right now) and an error is raised


Multiple添加的实体可能具有相同的主键。

Multiple added entities may have the same primary key.

因为在SaveChanges之前,所有ID均为0,并且代码无法区分

because, before the SaveChanges, all Ids are at 0 and the code can't differentiate them.

以下是POST:

async Task<ActionResult> Edit( FailureVM failure ) {
    if (ModelState.IsValid) {
        ...
        failure.OpenUserId = Await TryUpdateSignature(...);
        failure.DiagUserId = Await TryUpdateSignature(...);
        failure.CloseUserId = Await TryUpdateSignature(...);
        ...
        await db.SaveChangesAsync;
    }
}

和我的功能:

public static async Task<int?> TryUpdateSignature(MyDbContext db, Signature oldSignUser, Date? newDate, string userName)
{
    int? SignatureID = null; //Returns null if no date

    //Validate if there is a new date
    if ((IsNothing(oldSignUser) && newDate != null) || (oldSignUser != null && oldSignUser.DateSign != newDate))
    {
        Signature recSignature = Await db.Signature.FirstOrDefaultAsync(s => s.UserID == userName && s.DateSign == newDate);
        if (IsNothing(recSignature))
        {
            recSignature = new Signature;
            recSignature.UserID = userName;
            recSignature.DateSign = newDate;
            db.Signature.Add(recSignature);
        }

        SignatureID = recSignature.SignatureID;
    }
    else if (oldSignUser != null && newDate != null)
    {       //If no change, keep old signature
        SignatureID = oldSignUser.SignatureID;
    }

    return SignatureID;
}

我尝试使用对象而不是Ids,但是没有用。我可以事先插入签名,但我希望一次保存所有内容。

I tried using the object instead of the Ids but it didn't work. I could insert the Signature beforehand but I would prefer having everything saved at once.

在这一点上,我认为我的模型或方法存在问题。

At this point, I assume there's a problem with my model or my approach.

推荐答案

通过构造函数后,所有对象的ID均为0,因为默认值为0。由于PK必须标识数据库中的对象,因此EF甚至不会允许您插入具有相同id值的多个对象,更不用说尝试将这些对象保存回数据库了,因为它不知道如何标识每个元组(这甚至与EF有关,不仅出于一致性原因,还与DBMS有关,因为EF使用PK值作为默认的并发令牌。)

All your objects have Id's of 0 after going through the constructor, because 0 is the default int value. Because the PK has to identify the object in the database, EF won't even let you insert multiple objects with the same id values, let alone trying to save those back to the database, because it does not know how to identify each tuple (this even is of relevance to EF, not only DBMS for consistency reasons, because EF uses the PK values as default concurrency tokens).

解决方法是:您所有对象的PK值都不同。您的操作方式取决于您-在我的项目中,我们已经将所有要从一个通用基类保存到数据库的对象称为BOBase:

The way to solve this is to give all your objects distinct PK values. How you do it is up to you - in my project, we've let all objects that are meant to be saved to the database from one common base class, let's call it BOBase:

public abstract class BOBase
{
    public long Id { get; set; }

    public BOBase()
    {
        Id = DbTempId.Next();
    }
}

internal static class DbTempId
{
    private static long _next = -1;
    internal static long Next()
    {
        return _next--;
    }
}

一旦让所有BO都继承自该基类(并且不要隐藏继承的属性),新创建的对象的ID将为-1,-2等。我们甚至使用它来区分新对象和要更新的对象-新对象的ID为负,而现有对象的ID为正。

Once you let all your BO's inherit from this base class (and don't hide the inherited property), the Id's of newly created objects will be -1, -2 and so on. We even use this to differentiate between new and to be updated objects - new objects will have a negative Id, while already existing objects will have a positive one.

这篇关于如何在SaveChanges之前创建多个实体?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆