代码之家  ›  专栏  ›  技术社区  ›  Sanjeewa severino

实体框架自动填充错误的实体

  •  1
  • Sanjeewa severino  · 技术社区  · 8 年前

    我正在开发带有ASP.NET MVC、实体框架和WCF的音乐商店示例应用程序。

    这是一个分层应用程序,它为实体提供了一个公共层。

    我写了一个种子方法,它可以很好地工作,但是当我试图添加一个 Album Cart ,另一个副本 专辑 也添加到 专辑 表加副本 Artists 也添加了。当我在填充 购物车 对象。我添加了这个语句,因为当我创建视图时,它为 item.Album.Title 进入

    这是我的代码:

    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>
    

    问题是 :为什么它会以这种不寻常的方式自动填充,以及如何修复它?

    1 回复  |  直到 8 年前
        1
  •  1
  •   Sanjeewa severino    8 年前

    你有复制品是因为 AddToCart 方法,您实例化了一个新的上下文 MusicStoreEntities .上下文不知道 Album 你通过的实体 album 参数。

    因此,当您执行此代码时:

    cartItem = new Cart
    {
        // [...]
        Album = album
    };
    

    然后打电话来 db.Carts.Add(cartItem); ,的 cartItem 将打开 Added 州。EF还将检查 购物车项目 对象图并发现 专辑 未被新上下文跟踪(请记住,此实例来自方法的参数),然后默认情况下,它还会将该实体置于 补充 州。英孚也会这么做的 专辑 对象图形,您将打开该相册的艺术家 补充 也请说明。打电话时 db.SaveChanges(); ,每个实体 补充 状态将被视为在数据库中生成一个新的插入,所以这就是为什么要进行复制。

    要解决此问题,您可以致电 db.Attach(album) 并让上下文关注如下实体:

    using (MusicStoreEntities db = new MusicStoreEntities())
    {
         db.Albums.Attach(album);
    
        // [...]
    }
    

    或使用 专辑 例如,您可以只设置外键属性 AlbumId 然后摆脱 专辑 财产转让。因此,在创建新购物车项目时,您只需要这样做:

    cartItem = new Cart
    {
        AlbumId = album.AlbumId,
        CartId = ShoppingCartID,
        Count = 1,
        DateCreated = DateTime.Now
    };