【问题标题】:How to get primary key in Entity Framework for a new entry and set FK Relationship如何在实体框架中获取新条目的主键并设置 FK 关系
【发布时间】:2018-02-11 02:47:19
【问题描述】:

在我的 ASP.NET MVC 5 应用程序中,我需要获取为数据库中的特定条目生成的主键。此外,我需要获取该 ID 并在数据库中设置外键关系。我尝试了以下尝试,它似乎正在工作,但我不得不致电_context.SaveChanges() TWICE。

UI 行为:用户有一个下拉列表,其中包含推荐形式的公司列表。当未找到公司时,用户将在下拉列表中选择“其他”。它将显示一个文本框,用户将在其中输入公司名称。所以我需要将此公司添加到数据库中并将其链接到推荐行。

ReferralCompany之间的关系:

 dBModelBuilder.Entity<Company>()
            .HasMany(u => u.Referrals)
            .WithRequired(u => u.Company)
            .HasForeignKey(u => u.CompanyId);

模型类:

public class Company
{
    [Key]
    public int CompanyId { get; set; }
    public string CompanyName { get; set; }

    public ICollection<Referral> Referrals { get; set; }
    public ICollection<CoverLetter> CoverLetters { get; set; }
}

public class Referral
{
    [Key]
    public int ReferralId { get; set; }

    [Display(Name = "REFERRALS")]
    public string ReferralName { get; set; }

    public int? CoverLetterId { get; set; }
    public virtual CoverLetter CoverLetter { get; set; }

    public int CompanyId { get; set; }
    public virtual Company Company { get; set; }
}

视图模型:

public class Referral
{
    [Key]
    public int ReferralId { get; set; }

    [Display(Name = "REFERRALS")]
    public string ReferralName { get; set; }

    public int? CoverLetterId { get; set; }
    public virtual CoverLetter CoverLetter { get; set; }

    public int CompanyId { get; set; }
    public virtual Company Company { get; set; }
}

我在控制器操作中的尝试:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(ReferralViewModel viewModel)
    {
        var candidateId = User.Identity.GetUserId();

        var referral = new Referral
        {
            ReferralName = viewModel.ReferralName,
        };

        if (viewModel.CompanyId.HasValue)
        // if it is option 4 then we need to add it to the company table
        {
            if (!string.IsNullOrEmpty(viewModel.TempCompany))
            {
                var f = new Company
                {
                    CompanyName = viewModel.TempCompany
                };

                _context.Companies.Add(f);
               // ********FIRST CALL
                 _context.SaveChanges(); 

                _context.Referrals.Add(referral);
                 referral.CompanyId = f.CompanyId;
               // **********SECOND CALL
                _context.SaveChanges(); // SECOND CALL ------
            }
            else
            {
                referral.CompanyId = viewModel.CompanyId.Value;
                _context.Referrals.Add(referral);
                _context.SaveChanges();
            }
        }

        return RedirectToAction("ReferralCenter");
    }

问题:我可以一次拨打_context.SaveChanges(); 完成这些步骤吗?

编辑

使用此代码,我得到一个NullReferenceException

if (!string.IsNullOrEmpty(viewModel.TempCompany))
{
    var f = new Company
                {
                    CompanyName = viewModel.TempCompany
                };

    f.Referrals.Add(referral); // Referrals is NULL(EXCEPTION)
    _context.Companies.Add(f);
    // _context.SaveChanges();
    //_context.Referrals.Add(referral);
    // referral.CompanyId = f.CompanyId;
    _context.SaveChanges();
}

【问题讨论】:

  • 哪个表是父表,哪个表是子表?此外,在您的用例中,您有一个推荐屏幕,然后需要为该推荐分配一家公司,该公司在数据库中可能存在也可能不存在?
  • 我在问题中添加了 Fluent Api 关系。已编辑。
  • @MrSlim:是的,当它不存在时,用户选择一个名为“Others”的所谓“公司”(它本身就是公司表中的一行)并将实际公司名称放在文本框中
  • @MrSlim:我现在添加了整个控制器动作。你能看一次吗?

标签: c# sql asp.net-mvc entity-framework asp.net-mvc-5


【解决方案1】:

据我了解,FK 约束是在 EF 中管理的,只要它们在 DB 中进行配置。

如果在您的 EF 模型中,Referral 是 Company 的子代,则应该有一个可从 Company 对象实例访问的引荐集合。

更新 我刚刚构建了一个简单的示例 MVC Proj,2 个 SQL 表(CompanyId 上的推荐人和公司 FK)4 个公司,第 4 个是 OTHER,使用反向 POCO 构建了一个 EF 模型以提高速度,添加了一个带有脚手架和视图的控制器,并将我的控制器修改为下面。 (我只是插入日期时间而不是 tempCompanyName。这里生成的语法更像@ashin 的答案,但它对我有用。

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "ReferralId,CompanyId")] Referral referral)
    {
        if (ModelState.IsValid)
        {
            if (referral.CompanyId == 4)
            {
                var f = new Company() { Name = DateTime.Now.ToString() };
                referral.Company = f;
            }
            db.Referrals.Add(referral);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        ViewBag.CompanyId = new SelectList(db.Companies, "CompanyId", "Name", referral.CompanyId);
        return View(referral);
    }

我的公司模型确实实例化了一个新的推荐集合

    public Company()
    {
        Referrals = new System.Collections.Generic.List<Referral>();
    } 

【讨论】:

  • 请在问题中查看我的“问题”部分
  • 我的代码出现 NULL Reference 异常。请查看我的编辑。
  • 我需要在公司的构造函数中初始化推荐集合吗?
  • 我在公司的构造函数中没有任何东西我刚刚添加了构造函数,现在它可以工作了。那么这是否意味着当我设置一个 MANY 关系时,我应该始终将构造函数中的集合初始化为拇指规则?。
  • 它必须在某个地方初始化,我认为构造函数似乎是一个合适的地方。虽然了解 EF 配置的工作原理很重要,但为了获得启动和运行的绝对速度,我多年来一直在使用 Simon Hughes 反向 Poco 生成器,使用它提供了一种生成 EF 样板代码的统一方式。 marketplace.visualstudio.com/…
【解决方案2】:

如果您定义了导航属性,您可以一次性保存公司和推荐人,如下所示:

if (!string.IsNullOrEmpty(viewModel.TempCompany))
{
   var f = new Company
   {
        CompanyName = viewModel.TempCompany
   };
   referral.Company = f;
   _context.SaveChanges();
}

EF 将负责设置 FK。

编辑

已更新代码以包含 cmets 中提到的 _context.Referrals.Add(referral)

if (!string.IsNullOrEmpty(viewModel.TempCompany))
{
   var f = new Company
   {
        CompanyName = viewModel.TempCompany
   };

   referral.Company = f;
   _context.Referrals.Add(referral);
   _context.SaveChanges();
}

【讨论】:

  • 请在问题中查看我的“问题”部分
  • Ef将FK设置为​​公司表“其他”(行值)的PK
  • 我相信如果 _context.Referrals.Add(referral) 被调用,这段代码会起作用,所以 +1
  • 我看到了这个问题的初始版本,它非常小。我假设referral 对象已经被上下文加载了。已编辑我的答案以包括 Slim 提到的更改。谢谢! :)
猜你喜欢
  • 1970-01-01
  • 2018-10-25
  • 2013-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多