1

我有一个这样定义的表:

CREATE TABLE [dbo].[Sitemap](
        [EntityId] [int] NOT NULL,
        [PageUrl] [nvarchar](400) NOT NULL,
        [Frequency] [nvarchar](400) NOT NULL,
[PageType] [nvarchar](400) NOT NULL,
[UpdatedOn] [datetime] NOT NULL,
CONSTRAINT [PK_Sitemap] PRIMARY KEY CLUSTERED 
(
[EntityId] ASC,
[PageType] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
   IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

我去了我的 edmx 文件并从数据库进行了更新。它导入了所有内容,但没有将两个字段都标记为主键。我尝试将第二个字段添加为主键,但它仍然不会将它们视为组合。

我遇到的问题是当我在具有类似条目的表上运行更新时,例如

EntityId = 1, PageType = 'Product',.... 和 EntityId = 1, PageType = 'Artist',...

我收到一条错误消息:

ObjectStateManager 中已存在具有相同键的对象。ObjectStateManager 无法跟踪具有相同键的多个对象。

如何让我的模型或代码正确使用复合作为主键?还是我必须制作某种复合字段才能做到这一点?

更新

我的代码是 NopCommerce 1.90 的一个分支

因此,我添加了一个接口和服务,并将其注册到 IoC 解析器。

对于这个表,我有以下类:

//------------------------------------------------------------------------------
// The contents of this file are subject to the nopCommerce Public License Version 1.0 ("License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at  http://www.nopCommerce.com/License.aspx. 
// 
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. 
// See the License for the specific language governing rights and limitations under the License.
// 
// The Original Code is nopCommerce.
// The Initial Developer of the Original Code is NopSolutions.
// All Rights Reserved.
// 
// Contributor(s): _______. 
//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using NopSolutions.NopCommerce.BusinessLogic.CustomerManagement;
using NopSolutions.NopCommerce.BusinessLogic.Infrastructure;
using NopSolutions.NopCommerce.BusinessLogic.Payment;
using NopSolutions.NopCommerce.BusinessLogic.Promo.Affiliates;
using NopSolutions.NopCommerce.BusinessLogic.Promo.Discounts;
using NopSolutions.NopCommerce.BusinessLogic.Shipping;
using NopSolutions.NopCommerce.BusinessLogic.Tax;

namespace NopSolutions.NopCommerce.BusinessLogic.SEO.Sitemaps
{
    /// <summary>
    /// Represents a Sitemap
    /// </summary>
    [Serializable]
    public partial class Sitemap : BaseEntity
    {
        #region Utilities

        #endregion

        #region Properties

        /// <summary>
        /// Gets or Sets EntityId (Product ID, Show ID, etc.)
        /// </summary>
        public int EntityId { get; set; }

        /// <summary>
        /// Gets or sets the Page Url
        /// </summary>
        public string PageUrl { get; set; }

        /// <summary>
        /// Gets of set the Page Frequency (Should be one of the following - Always, Hourly, Daily, Weekly, Monthly, Yearly, Never)
        /// </summary>
        public string Frequency { get; set; }

        /// <summary>
        /// Gets or sets the page type. For example: Product, or Show
        /// </summary>
        public string PageType { get; set; }

        /// <summary>
        /// Gets or sets the date and time of sitemap entry update
        /// </summary>
        public DateTime UpdatedOn { get; set; }

        #endregion
    }
}

然后我有接口和服务:

界面:

  //------------------------------------------------------------------------------
  // The contents of this file are subject to the nopCommerce Public License Version 1.0 ("License"); you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at  http://www.nopCommerce.com/License.aspx.
    //
    // Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
    // See the License for the specific language governing rights and limitations under the License.
    //
    // The Original Code is nopCommerce.
    // The Initial Developer of the Original Code is NopSolutions.
    // All Rights Reserved.
    //
    // Contributor(s): _______.
    //------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using NopSolutions.NopCommerce.BusinessLogic.CustomerManagement;
using NopSolutions.NopCommerce.BusinessLogic.Payment;
using NopSolutions.NopCommerce.BusinessLogic.Shipping;
using NopSolutions.NopCommerce.Common;

namespace NopSolutions.NopCommerce.BusinessLogic.SEO.Sitemaps
{
    /// <summary>
    /// Sitemap service
    /// </summary>
    public partial interface ISiteMapService
    {
        /// <summary>
        /// Gets a Sitemap entry based on url.
        /// </summary>
        /// <param name="url">Fully Qualified URL (e.g. http://www.onlinesheetmusic.com/default.aspx)</param>
        /// <returns></returns>
        Sitemap GetSitemap(string url);

        /// <summary>
        /// Gets the most recent entry to the sitemap table
        /// </summary>
        /// <returns></returns>
        Sitemap GetLastAddedSitemap(string pageType);

        /// <summary>
        /// Gets a list of Sitemap entries that are in the init state of the given Page Type
        /// </summary>
        /// <param name="pageType">Page Type</param>
        /// <returns></returns>
        List<Sitemap> GetInitEntries(string pageType);

        /// <summary>
        /// Bool to determine if a given pageType has any entries in the init state.
        /// </summary>
        /// <param name="pageType"></param>
        /// <returns></returns>
        bool IsInit(string pageType);

        void InitSitemap(string pageType, int startProdId = 0);

        /// <summary>
        /// Inserts a sitemap entry
        /// </summary>
        /// <param name="order">Order</param>
        void InsertSitemap(Sitemap sm);

        /// <summary>
        /// Updates the order
        /// </summary>
        /// <param name="order">The order</param>
        void UpdateSitemap(Sitemap sm);
    }
}

服务:

//------------------------------------------------------------------------------
// The contents of this file are subject to the nopCommerce Public License Version 1.0 ("License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at  http://www.nopCommerce.com/License.aspx.
//
// Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
// See the License for the specific language governing rights and limitations under the License.
//
// The Original Code is nopCommerce.
// The Initial Developer of the Original Code is NopSolutions.
// All Rights Reserved.
//
// Contributor(s): _______.
//------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using NopSolutions.NopCommerce.BusinessLogic.Audit;
using NopSolutions.NopCommerce.BusinessLogic.Caching;
using NopSolutions.NopCommerce.BusinessLogic.Configuration.Settings;
using NopSolutions.NopCommerce.BusinessLogic.CustomerManagement;
using NopSolutions.NopCommerce.BusinessLogic.Data;
using NopSolutions.NopCommerce.BusinessLogic.Directory;
using NopSolutions.NopCommerce.BusinessLogic.Infrastructure;
using NopSolutions.NopCommerce.BusinessLogic.Localization;
using NopSolutions.NopCommerce.BusinessLogic.Messages;
using NopSolutions.NopCommerce.BusinessLogic.Messages.SMS;
using NopSolutions.NopCommerce.BusinessLogic.Payment;
using NopSolutions.NopCommerce.BusinessLogic.Products;
using NopSolutions.NopCommerce.BusinessLogic.Products.Attributes;
using NopSolutions.NopCommerce.BusinessLogic.Profile;
using NopSolutions.NopCommerce.BusinessLogic.Promo.Discounts;
using NopSolutions.NopCommerce.BusinessLogic.QuickBooks;
using NopSolutions.NopCommerce.BusinessLogic.Security;
using NopSolutions.NopCommerce.BusinessLogic.Shipping;
using NopSolutions.NopCommerce.BusinessLogic.Tax;
using NopSolutions.NopCommerce.Common;
using NopSolutions.NopCommerce.Common.Extensions;
using NopSolutions.NopCommerce.Common.Utils;
using NopSolutions.NopCommerce.Common.Utils.Html;

namespace NopSolutions.NopCommerce.BusinessLogic.SEO.Sitemaps
{
    /// <summary>
    /// Sitemap service
    /// </summary>
    public partial class SiteMapService : ISiteMapService
    {
        #region Fields

        /// <summary>
        /// Object context
        /// </summary>
        private readonly NopObjectContext _context;

        /// <summary>
        /// Cache service
        /// </summary>
        private readonly ICacheManager _cacheManager;

        #endregion Fields

        #region Ctor

        /// <summary>
        /// Ctor
        /// </summary>
        /// <param name="context">Object context</param>
        public SiteMapService(NopObjectContext context)
        {
            this._context = context;
            this._cacheManager = new NopRequestCache();
        }

        #endregion Ctor

        #region Utilities

        #endregion Utilities

        #region Methods

        /// <summary>
        /// Gets a sitemap entry
        /// </summary>
        /// <param name="url">The url of the sitempa item</param>
        /// <returns>Order</returns>
        public Sitemap GetSitemap(string url)
        {
            if (!url.IsNotNullOrEmpty())
                return null;

            var query = from sm in _context.Sitemaps
                        where sm.PageUrl.Contains(url)
                        select sm;
            var sitemap = query.SingleOrDefault();
            return sitemap;
        }

        public Sitemap GetLastAddedSitemap(string pageType)
        {
            var query = (from sm in _context.Sitemaps
                         where sm.PageType.Equals(pageType)
                         orderby sm.UpdatedOn descending
                         select sm).Take(1);

            var sitemap = query.SingleOrDefault();

            return sitemap;                        
        }

        public List<Sitemap> GetInitEntries(string pageType)
        {
            var query = (from sm in _context.Sitemaps
                         where sm.PageType.Equals(pageType)
                         && sm.Frequency == "Init"
                         select sm).Take(500);

            return query.ToList();
        }

        /// <summary>
        /// Bool to check if a given type has any entries in the init state.
        /// </summary>
        /// <param name="pageType">Page Type</param>
        /// <returns>True or False</returns>
        public bool IsInit(string pageType)
        {
            var query = (from sm in _context.Sitemaps
                         where sm.PageType.Equals(pageType)
                         && sm.PageUrl.Equals("Init")
                         select sm).Take(1);
            if (query == null)
                return true;
            else
                return false;
        }

        public void InitSitemap(string pageType, int startProdId = 0)
        {
            _context.Sp_SitemapInit(pageType, startProdId);
        }

        /// <summary>
        /// Inserts a sitemap entry
        /// </summary>
        /// <param name="sm">Sitemap Entry to Insert</param>
        public void InsertSitemap(Sitemap sm)
        {
            if (sm == null)
                throw new ArgumentNullException("sitemap");

            sm.PageUrl = CommonHelper.EnsureNotNull(sm.PageUrl);
            sm.PageType = CommonHelper.EnsureNotNull(sm.PageType);
            sm.Frequency = CommonHelper.EnsureNotNull(sm.Frequency);

            _context.Sitemaps.AddObject(sm);
            _context.SaveChanges();

        }

        /// <summary>
        /// Updates a sitemap entry
        /// </summary>
        /// <param name="sm">Sitemap Entry to update</param>
        public void UpdateSitemap(Sitemap sm)
        {
            if (sm == null)
                throw new ArgumentNullException("sitemap");

            sm.PageUrl = CommonHelper.EnsureNotNull(sm.PageUrl);
            sm.PageType = CommonHelper.EnsureNotNull(sm.PageType);
            sm.Frequency = CommonHelper.EnsureNotNull(sm.Frequency);

            if(_context.Sitemaps.Any(s => (s.PageUrl == sm.PageUrl || s.EntityId == sm.EntityId)))
            {
                if (!_context.IsAttached(sm))
                    _context.Sitemaps.Attach(sm);
            }
            else
            {
                _context.Sitemaps.AddObject(sm);
            }


            _context.SaveChanges();
        }

        #endregion Methods

        #region Properties

        /// <summary>
        /// Gets a value indicating whether cache is enabled
        /// </summary>
        public bool CacheEnabled
        {
            get
            {
                return IoC.Resolve<ISettingManager>().GetSettingValueBoolean("Cache.OrderManager.CacheEnabled");
            }
        }

        #endregion Properties
    }
}

当我打电话

var sitemapservice = IoC.Resolve<ISiteMapService>();
            sitemapservice.InitSitemap("Artist");
            var smEntries = sitemapservice.GetInitEntries("Artist");
            foreach (Sitemap sm in smEntries)
            {
                using (MvcMiniProfiler.MiniProfiler.StepStatic("Processing Entry: " + sm.EntityId + "," + sm.PageType))
                {
                    sm.Frequency = "Monthly";
                    sm.PageUrl = SEOHelper.GetUrl(this.ArtistService.GetArtistById(sm.EntityId), this.SettingManager.StoreUrl);

                    using (MvcMiniProfiler.MiniProfiler.StepStatic("Updating database"))
                    {
                        sitemapservice.UpdateSitemap(sm);
                    }
                    curCount++;
                }
            }

它应该获取 init 阶段的所有条目并使用正确的 url 设置它们,但无论出于何种原因,我不断收到错误消息,说 ObjectStateManager 中已经存在具有相同键的对象。虽然奇怪的是数据库似乎正在正确更新,但它一直给我这个错误。

4

1 回答 1

0

我想这就是你所指的...

public class CollectionItem
{
    public int CollectionId { get; set; }
    public int ItemId { get; set; }

    [RelatedTo(ForeignKey = "CollectionId")]
    public Collection Collection { get; set; }
    [RelatedTo(ForeignKey = "ItemId")]
    public Item Item { get; set; }
}

并像这样使用模型构建器

var builder = new ModelBuilder();
// ...
builder.Entity<CollectionItem>().HasKey(p=>new {p.CollectionId, p.ItemId});
// ...
model = builder.CreateModel();

希望这会有所帮助,我试图保持名称通用

于 2013-02-27T00:28:57.573 回答