我正在开发的音乐商店示例应用程序与ASP.NET的MVC,实体框架和WCF。
这是一个分层的应用程序,它有一个用于实体的公共层。
我已经写了一个种子方法,它工作得很好,但是当我试图向Cart
添加一个Album
时,另一个重复的Album
也被添加到Album
表中,同时还添加了重复的Artists
。当我在填充Cart
对象时添加Album = album语句时,就会发生这种情况。我添加了这条语句,因为当我创建视图时,它会为item.Album.Title
条目生成null
这是我的代码:
public static void AddToCart(Album album, string ShoppingCartID)
{
using (MusicStoreEntities db = new MusicStoreEntities())
{
// Get the matching cart and album instances
var cartItem = db.Carts.SingleOrDefault(
c => c.CartId == ShoppingCartID
&& c.AlbumId == album.AlbumId);
if (cartItem == null)
{
// Create a new cart item if no cart item exists
cartItem = new Cart
{
AlbumId = album.AlbumId,
CartId = ShoppingCartID,
Count = 1,
DateCreated = DateTime.Now,
Album = album
};
db.Carts.Add(cartItem);
}
else
{
// If the item does exist in the cart, then add one to the quantity
cartItem.Count++;
}
// Save changes
db.SaveChanges();
}
}
模型类:
namespace MusicStore.Core
{
[Serializable]
[DataContract]
//[Bind(Exclude = "AlbumId")]
public class Album
{
[DataMember]
[ScaffoldColumn(false)]
public int AlbumId { get; set; }
[DataMember]
[DisplayName("Genre")]
public int GenreId { get; set; }
[DataMember]
[DisplayName("Artist")]
public int ArtistId { get; set; }
[DataMember]
[Required(ErrorMessage = "An Album Title is required")]
[StringLength(160)]
public string Title { get; set; }
[DataMember]
[Required(ErrorMessage = "Price is required")]
[Range(0.01, 100.00, ErrorMessage = "Price must be between 0.01 and 100.00")]
public decimal Price { get; set; }
[DataMember]
[DisplayName("Album Art URL")]
[StringLength(1024)]
public string AlbumArtUrl { get; set; }
[DataMember]
public virtual Genre Genre { get; set; }
[DataMember]
public virtual Artist Artist { get; set; }
public virtual List<OrderDetail> OrderDetails { get; set; }
}
}
namespace MusicStore.Core
{
[Serializable]
[DataContract]
public class Cart
{
[Key]
[DataMember]
public int RecordId { get; set; }
[DataMember]
public string CartId { get; set; }
[DataMember]
public int AlbumId { get; set; }
[DataMember]
public int Count { get; set; }
[DataMember]
public System.DateTime DateCreated { get; set; }
[DataMember]
public virtual Album Album { get; set; }
}
}
种子方法:
namespace MusicStore.Data
{
internal class CommonDBInitializer : CreateDatabaseIfNotExists<MusicStoreEntities>
{
protected override void Seed(MusicStoreEntities context)
{
var genres1 = new List<Genre>
{
new Genre
{
Name = "Rock",
Description = "Rock",
Albums = new List<Album>()
},
new Genre
{
Name = "Jazz",
Description = "Jazz",
Albums = new List<Album>()
},
new Genre
{
Name = "Metal",
Description = "Metal",
Albums = new List<Album>()
},
new Genre
{
Name = "Alternative",
Description = "Alternative",
Albums = new List<Album>()
},
new Genre
{
Name = "Disco",
Description = "Disco",
Albums = new List<Album>()
},
new Genre
{
Name = "Blues",
Description = "Blues",
Albums = new List<Album>()
},
new Genre
{
Name = "Latin",
Description = "Latin",
Albums = new List<Album>()
},
new Genre
{
Name = "Reggae",
Description = "Reggae",
Albums = new List<Album>()
},
new Genre
{
Name = "Pop",
Description = "Pop",
Albums = new List<Album>()
},
new Genre
{
Name = "Classical",
Description = "Classical",
Albums = new List<Album>()
},
};
genres1.ForEach(d => context.Genres.Add(d));
context.SaveChanges();
var artist1 = new List<Artist>
{
new Artist
{
Name = "Aaron Copland & London Symphony Orchestra",
},
new Artist
{
Name = "Barry Wordsworth & BBC Concert Orchestra",
},
};
artist1.ForEach(d => context.Artists.Add(d));
context.SaveChanges();
var album1 = new List<Album>
{
new Album { Title = "The Best Of Men At Work", Price = 8.99M, AlbumArtUrl = "/Content/Images/placeholder.gif",Genre = genres1.FirstOrDefault(d => d.GenreId == 1), Artist = artist1.FirstOrDefault(d => d.ArtistId == 1) },
new Album { Title = "A Copland Celebration, Vol. I", Price = 8.99M, AlbumArtUrl = "/Content/Images/placeholder.gif",Genre = genres1.FirstOrDefault(d => d.GenreId == 2),Artist = artist1.FirstOrDefault(d => d.ArtistId == 2) },
};
album1.ForEach(s => context.Albums.Add(s));
context.SaveChanges();
}
}
控制器:
namespace MusicStore.Web.Controllers
{
public class ShoppingCartController : Controller
{
MusicShoppingCartMgr.Cart serviceref1 = new MusicShoppingCartMgr.Cart();
MusicShoppingCartMgr.iShoppingCart servicemethodref1 = new iShoppingCartClient();
//
// GET: /ShoppingCart/
public ActionResult Index()
{
var cart = ShoppingCart.GetCart(this.HttpContext);
// Set up our ViewModel
var viewModel = new ShoppingCartViewModel
{
CartItems = cart.GetCartItems(cart.ShoppingCartId),
CartTotal = cart.GetTotal(cart.ShoppingCartId)
};
// Return the view
return View(viewModel);
}
//
// GET: /Store/AddToCart/5
public ActionResult AddToCart(int id)
{
var addedAlbum = servicemethodref1.GetAlbum(id);
// Add it to the shopping cart
var cart = ShoppingCart.GetCart(this.HttpContext);
cart.AddToCart(addedAlbum, cart.ShoppingCartId);
// Go back to the main store page for more shopping
return RedirectToAction("Index");
}
}
}
查看:
@model MusicStore.Web.ViewModels.ShoppingCartViewModel
@{
ViewBag.Title = "Shopping Cart";
}
<script src="/Scripts/jquery-1.10.2.min.js" type="text/javascript"></script>
<h3>
<em>Review</em> your cart:
</h3>
<p class="button">
@Html.ActionLink("Checkout >>", "AddressAndPayment", "Checkout")
</p>
<div id="update-message">
</div>
<table>
<tr>
<th>
Album Name
</th>
<th>
Price (each)
</th>
<th>
Quantity
</th>
<th></th>
</tr>
@foreach (var item in Model.CartItems)
{
<tr id="row-@item.RecordId">
<td>
@Html.ActionLink(item.Album.Title, "Details", "Store", new { id = item.AlbumId }, null)
</td>
<td>
@item.Album.Price
</td>
<td id="item-count-@item.RecordId">
@item.Count
</td>
<td>
<a href="#" class="RemoveLink" data-id="@item.RecordId">Remove from cart</a>
</td>
</tr>
}
<tr>
<td>
Total
</td>
<td></td>
<td></td>
<td id="cart-total">
@Model.CartTotal
</td>
</tr>
</table>
的问题是:为什么它会以如此不寻常的方式自动填充,以及如何修复它?
发布于 2018-06-10 12:46:29
复制是因为在AddToCart
方法中实例化了一个新的上下文MusicStoreEntities
。该上下文不知道您通过album
参数传递的Album
实体的任何信息。
所以当你写这段代码的时候:
cartItem = new Cart
{
// [...]
Album = album
};
名为db.Carts.Add(cartItem);
,cartItem
将处于Added
状态。EF还将检查cartItem
对象图,并发现album
未被新上下文跟踪(请记住,此实例来自您的方法的参数),然后默认情况下,它也会将该实体置于Added
状态。EF将对album
对象图执行相同的操作,您也将在Added
状态上获得该专辑的艺术家。当调用db.SaveChanges();
时,每个具有Added
状态的实体都会被认为是在数据库中生成一个新的插入,所以这就是为什么要进行复制。
要解决这个问题,您可以调用db.Attach(album)
,让context来处理实体,如下所示:
using (MusicStoreEntities db = new MusicStoreEntities())
{
db.Albums.Attach(album);
// [...]
}
或者不使用album
实例,您可以只设置外键属性AlbumId
,而不使用Album
属性赋值。因此,在创建新购物车项目时,您将拥有以下内容:
cartItem = new Cart
{
AlbumId = album.AlbumId,
CartId = ShoppingCartID,
Count = 1,
DateCreated = DateTime.Now
};
https://stackoverflow.com/questions/50778136
复制相似问题