MVC5 EF实体显然正在保存,但是在检索时为null [英] MVC5 EF Entity apparently saving, but is null when retrieved

查看:111
本文介绍了MVC5 EF实体显然正在保存,但是在检索时为null的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Account类,其中包含一个Payments列表,该列表中包含一个Products列表,这些列表分别是PendingSoldRefunded.

I have an Account class that holds a list of Payments, which holds a list of Products that are Pending, Sold or Refunded.

选择当来支付,我可以将它们添加到一个对象,然后保存整个对象到

When selecting the Products to pay for, I can add them into a Payment object and then save the whole object to an Account.

但是,当我在Pay操作中检索帐户时,Account.Payments为空.

However, when I retrieve the account in the Pay action, Account.Payments is null.

这是AddProduct动作:

public ActionResult AddProduct(List<Product> products)
{
    //var acc = Account.FetchAccountFromIdentity(User.Identity.GetUserName());
    var username = User.Identity.GetUserName();
    var acc = db.Accounts.First(u => u.EmailAddress == username);
    var payment = new Payment();

    foreach (var product in products)
    {
        if (product.IsSelected)
        {
            var tempProduct = db.Products.Find(product.ProductID);
            payment.Products.Add(tempProduct);
            payment.PaymentStatus = enPaymentStatus.Pending;
            payment.Gross += tempProduct.Price;
            payment.Vat += tempProduct.Price * 0.2;
            payment.Net += payment.Gross - payment.Vat;
         }
    }
    payment.AccountID = acc;
    if (acc.Payments == null) acc.Payments = new List<Payment>();
    acc.Payments.Add(payment);
    db.SaveChanges();

    return RedirectToAction("Pay", "Products", new {id = acc.AccountID} );
}

此时

acc.Payments正确地填充了任何相关付款.

acc.Payments is correctly populated with any relevant payments at this point.

然后执行Pay操作:

    public ActionResult Pay(int? id)
    {
        var acc = db.Accounts.Find(id);
        var data = new AccountPaymentView
        {
            Account =  acc,
            Payment = acc.Payments.First(p => p.PaymentStatus == enPaymentStatus.Pending)
        };

        return View(data);
    }

acc.Payments现在为空!?

关于我必须做错什么的任何想法吗?

Any idea as to what I must be doing wrong?

编辑 现在具有帐户类别:

Edit Now with Account Class:

    public class Account
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int AccountID { get; set; }
        [Display(Name = "Title")]
        public string Salutation { get; set; }
        [Required]
        [Display(Name = "First Name")]
        public string FirstName { get; set; }
        [Required]
        [Display(Name = "Last Name")]
        public string LastName { get; set; }
        [Required]
        [DataType(DataType.Password)]
        [Display(Name = "Password")]
        public string Password { get; set; }
        [Required]
        [DataType(DataType.Password)]
        [Compare("Password", ErrorMessage = "Passwords do not match. Please try again.")]
        [Display(Name = "Confirm Password")]
        public string ConfirmPass { get; set; }
        [Required]
        [DataType(DataType.EmailAddress)]
        [Display(Name = "Email Address")]
        public string EmailAddress { get; set; }
        public virtual ICollection<Address> Addresses { get; set; }
        public virtual ICollection<Payment> Payments { get; set; }
        public DateTime CreatedOn { get; set; }
        public virtual  ICollection<DateTime> VistsList { get; set; }
        public bool IsDeleted { get; set; }
        public enAccountType AccountType { get; set; }
}

编辑2 这是DBContext上的OnModelCreating方法(已删除不相关的部分).我要我错过明显的东西吗?

Edit 2 Here is the OnModelCreating method on the DBContext (Removed unrelated parts). I've got to me missing something glaringly obvious?

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Properties<DateTime>()
        .Configure(c => c.HasColumnType("datetime2"));

    modelBuilder.Entity<Account>().HasOptional(x => x.Addresses).WithMany();
    modelBuilder.Entity<Account>().HasOptional(x => x.Payments).WithMany();
    modelBuilder.Entity<Payment>().HasOptional(x => x.Products).WithMany();
    modelBuilder.Entity<Payment>().HasOptional(x => x.AccountID);
    modelBuilder.Entity<Payment>().HasKey(x => x.PaymentID);

}

编辑3 签出Account.FetchAccountFromIdentity()并打开一个新的上下文.因此,该内容已被删除,我现在在AddProduct方法(上面更新的代码)中使用了上下文.

Edit 3 Checked out the Account.FetchAccountFromIdentity() and it does open a new context. So that has now been removed and I now use a context within the AddProduct method (code updated above).

现在保存时出现以下错误!!!

Now I am getting the following error when saving!!!

An object of type 'System.Collections.Generic.List`1[[PPPv2.Models.Payment, PPPv2,
Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]' 
cannot be set or removed from the Value property of an EntityReference of type 'PPPv2.Models.Payment'.

我尝试在OnModelCreating方法中强制使用PK关系,但这似乎无济于事.

I've tried forcing the PK relationships in the OnModelCreating method, but it didn't seem to help.

为清楚起见,这是Payment类:

For clarity, here is the Payment class:

public class Payment
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int PaymentID { get; set; }
    public virtual Account AccountID { get; set; }
    public virtual ICollection<Product> Products { get; set; }
    public double Gross { get; set; }
    public double Net { get; set; }
    public double Vat { get; set; }
    public string TransactionCode { get; set; }
    public enPaymentStatus PaymentStatus { get; set; }
    public bool IsDeleted { get; set; }
    public DateTime PaidOn { get; set; }

    public Payment()
    {
        Products = new List<Product>();
        Gross = 0.0;
        Net = 0.0;
        Vat = 0.0;
        IsDeleted = false;
        PaidOn = new DateTime(2000, 1, 1, 0, 0,0);
    }

}

编辑4 根据要求,这是产品型号:

Edit 4 As requested, here is the Product model:

public class Product 
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ProductID { get; set; }
    public string Name   { get; set; }
    public string Description { get; set; }
    [DataType(DataType.Currency)]
    [DisplayFormat(DataFormatString = "£{0:#,###0.00}")]
    public double Price { get; set; }
    [DataType(DataType.Currency)]
    [Display(Name = "Total Estimated Legal Cost")]
    [DisplayFormat(DataFormatString = "£{0:#,###0.00}")]
    public double EstimatedTotalLegalCost { get; set; }
    public virtual ICollection<Overview> Overviews { get; set; }
    public virtual ICollection<Process> Processes { get; set; }
    public DateTime CreatedOn { get; set; }
    public DateTime LastUpdated { get; set; }
    public bool IsSelected { get; set; }
    public bool IsDeleted { get; set; }
}

推荐答案

如果查看Entity Framework生成的表,则会发现其中只有三个.给定您的数据模型,应该有将AccountPayment对象相互映射的联结表(PaymentProduct相同),您可能需要对其他集合执行相同的操作有).

If you look at the tables that the Entity Framework has generated, you'll see there's only three of them. Given your data model, there should be junction tables that map Account and Payment objects to one another (same goes for Payment and Product, and you'll likely need to do the same for the other collections you have).

关于无法将ListList强制转换为单个数据的异常是因为您的数据模型指示Products是一个集合,而数据库表实际上将其存储为外部- PaymentProduct之间的关键(即单个实体)关系.

The exception you are getting regarding being unable to cast a List of Products to a single one is because your data model indicated that Products was a collection, yet the database table was actually storing this as foreign-key (i.e., single entity) relationship between Payment and Product.

如果我将OnModelCreating方法中的代码更改为以下代码,则您的AddProducts方法将按预期工作.

If I change the code in the OnModelCreating method to the following, your AddProducts method works as intended.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));

    modelBuilder.Entity<Account>().HasMany(x => x.Addresses)
        .WithMany().Map(t => t.ToTable("AccountAddresses"));
    modelBuilder.Entity<Account>().HasMany(x => x.Payments)
        .WithMany().Map(t => t.ToTable("AccountPayments"));
    modelBuilder.Entity<Payment>().HasMany(x => x.Products)
        .WithMany().Map(t => t.ToTable("PaymentProducts"));
    modelBuilder.Entity<Payment>().HasOptional(x => x.AccountID);
    modelBuilder.Entity<Payment>().HasKey(x => x.PaymentID);
}

更改来自类似以下的代码:

The change was going from code like:

modelBuilder.Entity<Payment>().HasOptional(x => x.Products).WithMany();

收件人:

modelBuilder.Entity<Payment>().HasMany(x => x.Products).WithMany().Map(t => t.ToTable("PaymentProducts"));

这样做可以指示实体框架创建连接表,以使Payment可以保存Products的集合.

Doing so instructs Entity Framework to create the junction tables that allow a Payment to hold a collection of Products.

这篇关于MVC5 EF实体显然正在保存,但是在检索时为null的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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