2010-04-20 2 views
0

나는 (1) 피드, (2) 프로덕션 데이터베이스가 있습니다. 피드 데이터베이스는 우리가 매일 얻는 클라이언트 파일에서 제공되며, 나의 견해에서 읽기 전용 소스입니다. 피드 파일이 수신되면 피드 앱은 해당 작업을 수행 한 다음 최종적으로 프로덕션 사이트에서 웹 서비스를 호출합니다. 그런 다음이 웹 서비스는 피드 DB와 Prod DB 간의 동기화를 수행합니다. 본질적으로 이것은 의사 코드 :C#, LINQ 배치 항목 -이 작업을 수행하는 가장 좋은 방법은 무엇입니까?

  • 이 개체에 대한 LINQ를 사용하여 동일한 클라이언트
  • 에 대한 모든 자극 항목을 가져 오기 클라이언트
  • 에 대한 모든 피드 항목을 가져 오기 수 (1) UPDATE의 원인이 모든 항목 , (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); 
         } 
        } 
    } 
    

    예, 나는 더 효율적이 알고 :

  • 프로세스 업데이트
  • 프로세스 DELETES
  • 프로세스 삽입, 업데이트를 분리 및 삭제를 코드의 핵심 부분을 위해

를 삽입 이것을하는 방법과 나는 그들을 사용하기 시작했습니다. 그러나 위의 코드는 비교적 빠르게 작동하며 데이터를 3 List <> 세트로 나눕니다.

제 질문은 _dbRiv.SaveChanges() 메소드를 다루는 것에 관한 것입니다. 내가 발행 할 때 으로 표시되어 3 세트 모두를 끕니다 (위). 나는 유일한 키 위반을 추적하려고 노력하고 있는데, 이것으로 배치에서 제약 조건을 위반 한 하나 또는 두 개의 레코드를 찾지 못하고있다. 나는 LINQ for SQL이 실제로 어떻게 작동하는지에 대한 생각에서 어딘가에 뭔가를 놓쳤을 것이라고 확신한다. 내가하고 싶은 무엇

은 다음과 같습니다

  • 은 업데이트에 저장을 실행합니다. 다른 작업을 수행하십시오 다음,
  • DELETES 만 저장을 실행하십시오. 다른 것들을 수행하십시오 다음,
  • INSERT에서 한개 씩 저장 (지금은 현재)을 실행하십시오.

한 번에 하나의 배치에 SaveChanges를 발행 할 수있는 방법이 있습니까?
InsertProductList 개체를 foreach하고 한 번에 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() 등이 없습니다. –

+0

흠 .. Linq에서 SQL 또는 Entity Framework를 사용하고 있습니까? –

+0

엔티티 프레임 워크 - 위 코드를 추가했습니다 ... –

관련 문제