나는 (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를 이용하는 더 좋은 방법 등을 제안한다면, 나는 그것을 고맙게 생각할 것이다. 엔티티간에 조인을하는 아주 매끄러운 방법이 있으며 발에서 자신을 쏘기보다는 배우고 싶습니다.
내가 제안한 방법을 찾지 못했습니다. _dbRiv에는 SubmitCHanges() 메소드가없고 _dbRiv.Product.DeleteAllOnSubmit() 등이 없습니다. –
흠 .. Linq에서 SQL 또는 Entity Framework를 사용하고 있습니까? –
엔티티 프레임 워크 - 위 코드를 추가했습니다 ... –