2010-04-20 102 views
0

我有2個數據庫 - (1)飼料,(2)生產。 feeds數據庫是從我們每天獲得的客戶端文件中提供的,並且從我的角度來看,它是隻讀數據源。當收到供稿文件時,供稿應用程序會執行其操作,然後最終調用生產站點上的Web服務。然後,此Web服務在提要數據庫和Prod數據庫之間進行同步。在本質上,這是僞代碼:C#,LINQ批處理項目 - 執行此操作的最佳方法是什麼?

  • 獲取所有飼料項目爲客戶
  • 獲取同一客戶端
  • 使用LINQ的對象都督促項目,得到(1)導致的全部更新項目,(2)導致DELETE的所有項目和(3)導致INSERT的所有項目。
  • 處理更新
  • 進程刪除
  • 過程將

對於鐵心片的代碼分隔插入,更新和刪除:

List<model.AutoWithImage> feedProductList = _dbFeed.AutoWithImage.Where(feedProduct => feedProduct.ClientID == ClientID).ToList(); 
List<model.vwCompanyDetails> companyDetailList = _dbRiv.vwCompanyDetails.Where(feedProduct => feedProduct.ClientID == ClientID).ToList(); 
foreach (model.vwCompanyDetails companyDetail in companyDetailList) 
{ 
    List<model.Product> rivProductList = _dbRiv.Product.Include("Company").Where(feedProduct => feedProduct.Company.CompanyId == companyDetail.CompanyId).ToList(); 

    foreach (model.AutoWithImage feedProduct in feedProductList) 
    { 
     bool alreadyExists = false; 
     model.Company company = null; 
     foreach (model.Product rivProduct in rivProductList) 
     { 
      if (feedProduct.StockNumber == rivProduct.SKU) 
      { 
       alreadyExists = true; 

       // Active feed items... 
       if (feedProduct.Active) 
       { 
        // Changed since last sync... 
        if (feedProduct.Updated > rivProduct.LastFeedUpdate) 
        { 
         model.Product updateProduct = new model.Product(); 
         updateProduct.ProductId = rivProduct.ProductId; 
         // removed for brevity 
         updateProductList.Add(updateProduct); 
        } 
        // Not changed since last sync... 
        else if (feedProduct.Updated <= rivProduct.LastFeedUpdate) 
        { 
         //nop 
        } 
       } 
       // No longer active feed products... 
       else if (!feedProduct.Active) 
       { 
        model.Product deleteProduct = new model.Product(); 
        deleteProduct = rivProduct; 
        // removed for brevity 
        deleteProductList.Add(deleteProduct); 
       } 
      } 

      if (company == null) 
       company = rivProduct.Company; 
     } 

     // Found feedProduct new product... 
     if (!alreadyExists) 
     { 
      model.Product insertProduct = new Product(); 
      insertProduct.ProductId = Guid.NewGuid(); 
      // removed for brevity 
      insertProductList.Add(insertProduct); 
     } 
    } 
} 

是的,我知道有更有效的這樣做的方法,我開始使用它們。但是,上面的代碼工作起來相對較快,並將我的數據分解爲3個列表(列表<>集合)。

我的問題更多的是處理_dbRiv.SaveChanges()方法。當我發行它出現發射所有3套(以上)。我試圖追查一個獨特的密鑰違規行爲,並且在一批中我找不到違反約束條件的一兩條記錄。我確信我在思考LINQ for SQL如何真正起作用時錯過了某個地方。

我希望做的是:

  • 上剛剛更新執行一個保存。 做一些其他的東西然後,
  • 執行保存在只有DELETES。 做一些其他的東西然後,
  • 執行保存,一個接一個(現在) 上插入。

是否有某種方法可以一次對一個批次發出SaveChanges?
有沒有一種方法來foreach InsertProductList對象,並一次做一個SaveChanges一行? 我吠叫了錯誤的樹嗎?


編輯: 雖然我知道我可以調用從EF一個存儲過程,我的目的是要了解如何將存儲過程轉換爲EF。

我寫的東西我想在SQL在這裏它(這工作正是我們需要它):

SET ANSI_NULLS ON 
GO 

SET QUOTED_IDENTIFIER ON 
GO 

ALTER PROC [dbo].[ExecuteSync] @ClientID AS BIGINT AS 
BEGIN 
    DECLARE @cid UNIQUEIDENTIFIER 

    DECLARE c1 CURSOR FOR 
    SELECT CompanyID FROM CompanyDetails WHERE ClientID = @ClientID 
    OPEN c1 
    FETCH NEXT FROM c1 INTO @cid 
    WHILE @@FETCH_STATUS = 0 
    BEGIN 
     SET NOCOUNT ON 
     SELECT 'Syncing feed data for ' + CompanyName FROM Company WHERE CompanyId = @cid 
     SET NOCOUNT OFF 
     -- n/a -------------------------------------------------------------------------------------------------------------------------------------------------------------------- 
     --SELECT a.* 
     --  , p.* 
     -- FROM RIVFeeds..AutoWithImage a 
     -- INNER JOIN Product p ON a.StockNumber = p.SKU 
     -- WHERE ClientID = @ClientID 
     -- AND a.Active = 1 
     -- AND a.Updated <= p.LastFeedUpdate 

     -- Needs UPDATE ----------------------------------------------------------------------------------------------------------------------------------------------------------- 
     PRINT '--[ UPDATE ]--' 
     UPDATE Product 
      SET [Description] = '' 
      , [Image] = a.ImageURL 
      , isDeleted = a.Active^1 
      , isFromFeed = 1 
      , LastFeedUpdate = a.Updated 
      , LowestPrice = a.GuaranteedSalePrice 
      , RetailPrice = a.ListPrice 
      , [Title] = '' 
      , Updated = GETUTCDATE() 
      , UpdatedBy = 'Feed Sync Process' 
      FROM RIVFeeds..AutoWithImage a 
     INNER JOIN Product p ON a.StockNumber = p.SKU AND a.AutoID = p.alternateProductID 
     WHERE ClientID = @ClientID 
      AND p.CompanyID = @cid 
      AND a.Updated > p.LastFeedUpdate 

     -- Needs BACKUP ----------------------------------------------------------------------------------------------------------------------------------------------------------- 
     PRINT '--[ BACKUP #1 ]--' 
     INSERT INTO ProductDeleted(ProductId, alternateProductID, CompanyID, CharacterId, URLDomain, SKU, Title, Description, ButtonConfig, RetailPrice, LowestPrice, Image 
        , BackgroundColor, FontColor, buttonPositionCSS, isFromFeed, isDeleted, LastFeedUpdate, Created, CreatedBy, Updated, UpdatedBy) 
     SELECT p.ProductId, p.alternateProductID, p.CompanyID, p.CharacterId, p.URLDomain, p.SKU, p.Title, p.Description, p.ButtonConfig, p.RetailPrice, p.LowestPrice, p.Image 
        , p.BackgroundColor, p.FontColor, p.buttonPositionCSS, p.isFromFeed, p.isDeleted, p.LastFeedUpdate, p.Created, p.CreatedBy, GETUTCDATE(), 'Feed Sync Process' 
      FROM Product p 
     WHERE p.isDeleted = 1 
      AND p.CompanyID = @cid 

     -- Needs DELETE ----------------------------------------------------------------------------------------------------------------------------------------------------------- 
     PRINT '--[ DELETE #1 ]--' 
     DELETE FROM Product 
     WHERE CompanyID = @cid 
      AND isDeleted = 1 

     -- Needs INSERT ----------------------------------------------------------------------------------------------------------------------------------------------------------- 
     PRINT '--[ INSERT ]--' 
     INSERT INTO Product(ProductId, alternateProductID, CompanyID, CharacterId, URLDomain, SKU, Title, Description, ButtonConfig, RetailPrice, LowestPrice, Image 
        , BackgroundColor, FontColor, buttonPositionCSS, isFromFeed, isDeleted, LastFeedUpdate, Created, CreatedBy) 
     SELECT NEWID() 
      , a.AutoID 
      , @cid 
      , '' 
      , '' 
      , a.StockNumber 
      , '' 
      , '' 
      , '' 
      , a.ListPrice 
      , a.GuaranteedSalePrice 
      , COALESCE(a.ImageURL, '') 
      , '' 
      , '' 
      , '' 
      , 1 
      , 0 
      , a.Updated 
      , GETUTCDATE() 
      , 'Feed Sync Process' 
      FROM RIVFeeds..AutoWithImage a 
     WHERE a.ClientID = @ClientID 
      AND a.StockNumber NOT IN (SELECT p.sku FROM Product p WHERE CompanyID = @cid AND isFromFeed = 1) 
      AND a.AutoID NOT IN (SELECT p.alternateProductID FROM Product p WHERE CompanyID = @cid AND isFromFeed = 1) 
      AND a.Active = 1 

     --PRINT @cid 

     FETCH NEXT FROM c1 INTO @cid 
    END 
    CLOSE c1 
    DEALLOCATE c1 
END 
GO 

現在我寫它的代碼利用實體框架(尚未完成):

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using RivWorks.Model; 
using RivWorks.Model.Entities; 
using RivWorks.Model.Feeds; 
using RivWorks.Model.RivData; 
using model = RivWorks.Model.Entities; 

namespace RivWorks.Controller.Sync 
{ 
    public static class Feeds 
    { 
     #region Public Methods 
     public static bool Product(long ClientID) 
     { 
      bool retFlag = true; 
      DateTime startTime = DateTime.Now; 
      DateTime splitTime = startTime; 
      Guid companyID; 
      DateTime createdUpdated = DateTime.UtcNow; 
      string createdUpdatedBy = "Feed Sync Process"; 
      List<SyncMessage> Activity = new List<SyncMessage>(); 
      List<model.Product> insertProductList = new List<Product>(); 
      List<model.Product> updateProductList = new List<Product>(); 
      List<model.Product> deleteProductList = new List<Product>(); 

      using (RivEntities _dbRiv = new RivWorksStore(Stores.RivConnString).NegotiationEntities()) 
      { 
       using (FeedsEntities _dbFeed = new FeedStoreReadOnly(Stores.FeedConnString).ReadOnlyEntities()) 
       { 
        List<model.AutoWithImage> feedProductList = _dbFeed.AutoWithImage.Where(a => a.ClientID == ClientID).ToList(); 
        List<model.vwCompanyDetails> companyDetailList = _dbRiv.vwCompanyDetails.Where(a => a.ClientID == ClientID).ToList(); 

        foreach (model.vwCompanyDetails companyDetail in companyDetailList) 
        { 
         companyID = companyDetail.CompanyId; 
         List<model.Product> rivProductList = _dbRiv.Product.Include("Company").Where(a => a.Company.CompanyId == companyID).ToList(); 

         #region Handle UPDATES... 
         var updateFeedProductList = from f in feedProductList 
                join r in rivProductList 
                on f.AutoID equals r.alternateProductID 
                where f.Updated > r.LastFeedUpdate.Value || f.Active == false 
                select f; 
         var updateRivProductList = from r in rivProductList 
                join f in feedProductList 
                on r.alternateProductID equals f.AutoID 
                where f.Updated > r.LastFeedUpdate.Value || f.Active == false 
                select r; 

         foreach (model.AutoWithImage feedProduct in updateFeedProductList) 
         { 
          bool alreadyExists = false; 
          foreach (model.Product rivProduct in updateRivProductList) 
          { 
           if (feedProduct.StockNumber == rivProduct.SKU && feedProduct.AutoID == rivProduct.alternateProductID) 
           { 
            alreadyExists = true; 

            // Active feed items... 
            if (feedProduct.Active) 
            { 
             // Changed since last sync... 
             if (feedProduct.Updated > rivProduct.LastFeedUpdate) 
             { 
              rivProduct.ProductId = rivProduct.ProductId; 
              rivProduct.Company = rivProduct.Company; 
              rivProduct.alternateProductID = feedProduct.AutoID; 
              rivProduct.Description = String.Empty.EnforceNoNull(); 
              rivProduct.Image = feedProduct.ImageURL.EnforceNoNull(); 
              rivProduct.isDeleted = false; 
              rivProduct.isFromFeed = true; 
              rivProduct.LastFeedUpdate = feedProduct.Updated; 
              rivProduct.LowestPrice = feedProduct.GuaranteedSalePrice; 
              rivProduct.RetailPrice = feedProduct.ListPrice; 
              rivProduct.Title = String.Empty.EnforceNoNull(); 
              rivProduct.Updated = createdUpdated; 
              rivProduct.UpdatedBy = createdUpdatedBy; 
             } 
             // Not changed since last sync... 
             else if (feedProduct.Updated <= rivProduct.LastFeedUpdate) 
             { 
              // nop 
             } 
            } 
           } 
          } 
         } 
         _dbRiv.SaveChanges(); 
         #endregion 

         #region Handle DELETES... 
         List<model.Product> deleteRivProductList = _dbRiv.Product 
                     .Include("Company") 
                     .Where(a => a.Company.CompanyId == companyID 
                        && a.isDeleted == true) 
                     .ToList(); 
         // transfer to ProductDelete table... 
         foreach (model.Product delProduct in deleteRivProductList) 
         { 
          model.ProductDeleted productDeleted = new ProductDeleted(); 
          productDeleted.alternateProductID = delProduct.alternateProductID; 
          productDeleted.BackgroundColor = delProduct.BackgroundColor; 
          productDeleted.ButtonConfig = delProduct.ButtonConfig; 
          productDeleted.buttonPositionCSS = delProduct.buttonPositionCSS; 
          productDeleted.CharacterId = delProduct.CharacterId; 
          productDeleted.CompanyID = companyID; 
          productDeleted.Created = delProduct.Created; 
          productDeleted.CreatedBy = delProduct.CreatedBy; 
          productDeleted.Description = delProduct.Description; 
          productDeleted.FontColor = delProduct.FontColor; 
          productDeleted.Image = delProduct.Image; 
          productDeleted.isDeleted = delProduct.isDeleted; 
          productDeleted.isFromFeed = delProduct.isFromFeed; 
          productDeleted.LastFeedUpdate = delProduct.LastFeedUpdate; 
          productDeleted.LowestPrice = delProduct.LowestPrice; 
          productDeleted.ProductId = delProduct.ProductId; 
          productDeleted.RetailPrice = delProduct.RetailPrice; 
          productDeleted.SKU = delProduct.SKU; 
          productDeleted.Title = delProduct.Title; 
          productDeleted.Updated = createdUpdated; 
          productDeleted.UpdatedBy = createdUpdatedBy; 
          productDeleted.URLDomain = delProduct.URLDomain; 
          _dbRiv.AddToProductDeleted(productDeleted); 
         } 
         int moves = _dbRiv.SaveChanges(); 

         // delete the records... 
         foreach (model.Product delProduct in deleteRivProductList) 
         { 
          _dbRiv.DeleteObject(delProduct); 
         } 
         int deletes = _dbRiv.SaveChanges(); 
         #endregion 

         #region Handle INSERTS... 
         // to be written... 
         #endregion 
        } 
       } 
      } 
      return retFlag; // remember to set this... 
     } 
     #endregion 
    } 
} 

我知道現在有點混亂。我包括這個,所以如果任何人有關於如何更好地清理這個問題的建議,更好的方法來利用EF來做到這一點等,我將不勝感激。我知道在實體間進行聯結有一些非常光滑的方法,並且希望學習而不是在腳下開槍。

回答

0

我現在已經運行了代碼。由於沒有其他人在回答我必須假設我正朝着正確的方向前進。謝謝。

0

你究竟在哪裏插入或刪除記錄?我看到您將它們添加到insertProductListdeleteProductList,但您從未在表_dbRiv.Product上調用插入或刪除。

我想你要完成的是一樣的東西以下內容:

//perform all updates 
_dbRiv.SubmitChanges(); 

//perform all deletes 
_dbRiv.Product.DeleteAllOnSubmit(deleteProductList); 
_dbRiv.SubmitChanges(); 

//perform inserts, one at a time 
foreach(model.Product p in insertProductList) 
{ 
    _dbRiv.Product.InsertOnSubmit(p); 
    _dbRiv.SubmitChanges(); 
} 

但是,目前還不清楚你如何期待執行更新。看起來不是創建model.Product的新實例並設置其屬性,而應該更新rivProduct的屬性。否則,使用您的代碼,我相信您需要使用_dbRiv.Product.Attach(updateProduct, rivProduct)附加updateProduct,以便L2S知道哪些屬性發生了變化。

+0

我找不到您建議的方法。 _dbRiv沒有SubmitCHanges()方法,沒有_dbRiv.Product.DeleteAllOnSubmit()等。 – 2010-04-21 23:09:22

+0

嗯..你使用Linq to SQL或Entity Framework嗎? – 2010-04-22 01:24:32

+0

實體框架 - 我還添加了更多的代碼(上面)... – 2010-04-22 19:36:02

相關問題