MVC5 EF实体显然正在保存,但是在检索时为null [英] MVC5 EF Entity apparently saving, but is null when retrieved
问题描述
我有一个Account
类,其中包含一个Payments
列表,该列表中包含一个Products
列表,这些列表分别是Pending
,Sold
或Refunded
.
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生成的表,则会发现其中只有三个.给定您的数据模型,应该有将Account
和Payment
对象相互映射的联结表(Payment
和Product
相同),您可能需要对其他集合执行相同的操作有).
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).
关于无法将List
的List
强制转换为单个数据的异常是因为您的数据模型指示Products
是一个集合,而数据库表实际上将其存储为外部- Payment
和Product
之间的关键(即单个实体)关系.
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屋!