我使用Enumerable.Except检查内存中的DataTable是否与数据库中的表同步。
背景是:这个DataTable和其他经常使用的表存储在WebApplication的Cache中。但同时,我确信这不是一个好方法,因为它是一个很难再现/调试的严重错误的来源。
因此,我创建了一个函数来检查数据库和内存是否同步,否则将创建一个错误日志。这工作得很好。如果内存中有一行不在数据库中,这一行将显示在“数据库中的差异”下面,同样的情况也适用于相反的情况。但是,如果两个数据源( PK idRMA)中都存在行,并且某些值不同,则日志将包含两个版本的该行(在“数据库中的差异”和“数据库中的差异”下面)。一见钟情是不容易看出的。
Q:是否可以只选择导致Except认为第一个序列不在第二个序列的属性?
这是完整的函数(第一行是相关的):
Public Shared Sub CheckRmaMemoryInSyncWithDB()
Dim inSyncText As String
Dim color As Drawing.Color
Dim isInSync As Boolean
Dim daRma As New ERPModel.dsRMATableAdapters.RMATableAdapter
Dim tblRma = daRma.GetData()
Dim memory = (From rma In dsRMA.RMA
Where Not rma.IsfiChargeNull
Select rma.IdRMA, rma.fiCharge, rma.IMEI, rma.RMA_Number, rma.ModelID, rma.fiCustomer, SI_DPY = If(rma.IsSI_DPYNull, String.Empty, rma.SI_DPY), rma.fiStatus, rma.HasErrors).ToList
Dim dataBase = (From rma In tblRma
Where Not rma.IsfiChargeNull
Select rma.IdRMA, rma.fiCharge, rma.IMEI, rma.RMA_Number, rma.ModelID, rma.fiCustomer, SI_DPY = If(rma.IsSI_DPYNull, String.Empty, rma.SI_DPY), rma.fiStatus, rma.HasErrors).ToList
Dim notInDatabase = memory.Except(dataBase).ToList
Dim notInMemory= dataBase.Except(memory).ToList
If notInMemory.Any OrElse notInDatabase.Any Then
isInSync = False
inSyncText = "Database and Memory are NOT in Sync! Event-Log created."
Dim ex As New Exception("Database and Memory are NOT in Sync!")
Dim errInfo = String.Empty
If notInMemory.Any Then
errInfo &= "Difference in memory:" & Environment.NewLine
Dim memoryInfo = String.Join(Environment.NewLine, notInMemory)
errInfo &= memoryInfo & Environment.NewLine
End If
If notInDatabase.Any Then
errInfo &= "Difference in database:" & Environment.NewLine
Dim databaseInfo = String.Join(Environment.NewLine, notInDatabase)
errInfo &= databaseInfo & Environment.NewLine
End If
ErrorLog.WriteError(ex, errInfo)
Else
isInSync = True
inSyncText = "Database and Memory are in Sync, all RMA's are identical in both."
End If
Dim master = DirectCast(DirectCast(HttpContext.Current.CurrentHandler, Page).Master, ERPMaster)
color = If(isInSync, Drawing.Color.Green, Drawing.Color.Red)
master.showStatusMessage(inSyncText, True, color)
End SubNote:我可以比较所有的属性,但是我想知道是否有一种更简单的(LINQ)方法。基本上,我在寻找一种LINQ方法,只获取两种匿名类型序列的差异(因为我只选择DataRow的相关列来进行比较)。
编辑:我假设我必须在主键(idRMA)上加入这两者,但是我如何选择这些差异呢?如果联接不返回结果,则ID在第二个序列中不存在,并且可以记录所有属性。但是,如果在第二个序列中有一个适当的记录,我如何选择不同的属性?
Dim diff = From rmaMem In notInMemory
Join rmaDB In notInDatabase
On rmaMem.IdRMA Equals rmaDB.IdRMA
Select ...... ' i only want to select the properties in `rmaMem` that are different in `rmaDB` '发布于 2011-10-26 13:15:11
只要没有人知道更好的方法,我就会坚持笨拙的做法。只需再次比较它们,只显示不同的值,否则“相等”。
Public Shared Sub CheckRmaMemoryInSyncWithDB()
Dim inSyncText As String
Dim color As Drawing.Color
Dim isInSync As Boolean
Dim daRma As New ERPModel.dsRMATableAdapters.RMATableAdapter
Dim tblRma = daRma.GetData()
Dim memory = (From rma In dsRMA.RMA
Where Not rma.IsfiChargeNull
Select rma.IdRMA, rma.fiCharge, rma.IMEI, rma.RMA_Number, rma.ModelID, rma.fiCustomer, SI_DPY = If(rma.IsSI_DPYNull, String.Empty, rma.SI_DPY), rma.fiStatus, rma.HasErrors).ToList
Dim dataBase = (From rma In tblRma
Where Not rma.IsfiChargeNull
Select rma.IdRMA, rma.fiCharge, rma.IMEI, rma.RMA_Number, rma.ModelID, rma.fiCustomer, SI_DPY = If(rma.IsSI_DPYNull, String.Empty, rma.SI_DPY), rma.fiStatus, rma.HasErrors).ToList
Dim memoryDiff = memory.Except(dataBase).ToList
Dim databaseDiff = dataBase.Except(memory).ToList
If memoryDiff.Any OrElse databaseDiff.Any Then
isInSync = False
inSyncText = "Database and Memory are NOT in Sync! Error-Log created."
Dim ex As New Exception("Database and Memory are NOT in Sync!")
Dim errInfo As String = String.Empty
'following joins both sequences to detect differences
'note: completely missing RMA's will be detected later
Dim diff = From rmaMem In memoryDiff
Join rmaDB In databaseDiff
On rmaMem.IdRMA Equals rmaDB.IdRMA
Select rmaDB.IdRMA _
, fiCharge = If(rmaMem.fiCharge = rmaDB.fiCharge, "equal", String.Format("{0}/{1}", rmaMem.fiCharge, rmaDB.fiCharge)) _
, IMEI = If(rmaMem.IMEI = rmaDB.IMEI, "equal", String.Format("{0}/{1}", rmaMem.IMEI, rmaDB.IMEI)) _
, RMA_Number = If(rmaMem.RMA_Number = rmaDB.RMA_Number, "equal", String.Format("{0}/{1}", rmaMem.RMA_Number, rmaDB.RMA_Number)) _
, ModelID = If(rmaMem.ModelID = rmaDB.ModelID, "equal", String.Format("{0}/{1}", rmaMem.ModelID, rmaDB.ModelID)) _
, fiCustomer = If(rmaMem.fiCustomer = rmaDB.fiCustomer, "equal", String.Format("{0}/{1}", rmaMem.fiCustomer, rmaDB.fiCustomer)) _
, SI_DPY = If(rmaMem.SI_DPY = rmaDB.SI_DPY, "equal", String.Format("{0}/{1}", rmaMem.SI_DPY, rmaDB.SI_DPY)) _
, fiStatus = If(rmaMem.fiStatus = rmaDB.fiStatus, "equal", String.Format("{0}/{1}", rmaMem.fiStatus, rmaDB.fiStatus)) _
, HasErrors = If(rmaMem.HasErrors = rmaDB.HasErrors, "equal", String.Format("{0}/{1}", rmaMem.HasErrors, rmaDB.HasErrors))
If diff.Any Then
errInfo &= "Differences(memory/database):" & Environment.NewLine
errInfo &= String.Join(Environment.NewLine, diff) & Environment.NewLine
End If
Dim memoryIDs = (From rma In memory
Select rma.IdRMA).ToList
Dim databaseIDs = (From rma In dataBase
Select rma.IdRMA).ToList
Dim missingInMemory = databaseIDs.Except(memoryIDs)
Dim missingInDB = memoryIDs.Except(databaseIDs)
If missingInMemory.Any Then
Dim rmaInfo = From rma In dataBase
Join idRMA In missingInMemory
On idRMA Equals rma.IdRMA
Select rma
errInfo &= "Missing RMA's in memory:" & Environment.NewLine
errInfo &= String.Join(Environment.NewLine, rmaInfo) & Environment.NewLine
End If
If missingInDB.Any Then
Dim rmaInfo = From rma In memory
Join idRMA In missingInDB
On idRMA Equals rma.IdRMA
Select rma
errInfo &= "Missing RMA's in database:" & Environment.NewLine
errInfo &= String.Join(Environment.NewLine, rmaInfo)
End If
ErrorLog.WriteError(ex, errInfo)
Else
isInSync = True
inSyncText = "Database and Memory are in Sync, all RMA's are identical in both."
End If
Dim master = DirectCast(DirectCast(HttpContext.Current.CurrentHandler, Page).Master, ERPMaster)
color = If(isInSync, Drawing.Color.Green, Drawing.Color.Red)
master.showStatusMessage(inSyncText, True, color)
End Sub产生以下示例性输出:
Differences(memory/database):
{ IdRMA = 25878, fiCharge = equal, IMEI = equal, RMA_Number = equal, ModelID = equal, fiCustomer = equal, SI_DPY = 1207-1104/1206-1105, fiStatus = equal, HasErrors = equal }
Missing RMA's in database:
{ IdRMA = 25882, fiCharge = 1416, IMEI = 004401076362330, RMA_Number = RMA0022725, ModelID = 449, fiCustomer = 49, SI_DPY = , fiStatus = 17, HasErrors = False }
{ IdRMA = 25881, fiCharge = 1416, IMEI = 359419030480338, RMA_Number = RMA0022724, ModelID = 758, fiCustomer = 49, SI_DPY = 1207-1124, fiStatus = 18, HasErrors = False }顺便说一句,这种看似不一致的做法很容易被强迫。在与生产服务器并行的VisualStudio(Cassini)中启动应用程序,并删除/创建一些测试记录,或者到处更改一些值。
发布于 2011-10-26 11:30:25
我认为您需要像描述的这里那样创建一个自定义的相等比较器。最终,您将不得不以某种方式比较属性值,并且由于您使用的是Except(),所以您可以保持事物的一致性,并创建一个自定义比较器。
除此之外,您还可以编写一个单独的函数来为您完成这项工作。重要的是你喜欢什么。
编辑:
这是非常粗略的代码,但希望可以帮助您:
class Program
{
static void Main(string[] args)
{
var p1 = new Person();
p1.Name = "A";
p1.Age = 23;
var p2 = new Person();
p2.Name = "Ralph";
p2.Age = 56;
Diff(p1, p2);
}
private static void Diff(Person p1, Person p2)
{
var prop = p1.GetType().GetProperties();
var notMatchingProperties = new List<string>();
foreach(var p in prop)
{
var propName = p.Name;
var propValue1 = p1.GetType().GetProperty(propName).GetValue(p1, null);
var propValue2 = p2.GetType().GetProperty(propName).GetValue(p2, null);
if (!propValue1.Equals(propValue2))
{
notMatchingProperties.Add(propName);
}
}
foreach (var notMatchingProperty in notMatchingProperties)
{
Console.WriteLine(notMatchingProperty);
}
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}我不是一个反射专家,所以如果别人可以评论我的代码,那就太好了。
最后,我不确定缓存数据是否是这里最好的方法。您可能需要考虑将信息存储在数据库中。缓存的问题是,在任何时候,该网站可能被回收(或重新启动),您可以松散您的内存数据。
在数据库中拥有数据的另一个优点是,您可以直接在数据库上运行查询,以便知道哪些属性已经更改。在您的角度下,这就是我要做的-在数据库中创建一个表来存储您在缓存中拥有的信息。
发布于 2011-10-26 11:42:01
这不是在回答你的问题,所以如果它没有帮助的话,就放弃吧,但是你可能想要更多地思考你的设计。
此DataTable和其他常用表存储在WebApplication的缓存中。但同时,我确信这不是一个好方法,因为它是一个很难再现/调试的严重错误的来源。
这是红旗。DataTable不是线程安全的,所以您可能永远不应该修改Cache中的线程安全。如果不进行同步,肯定会给您带来难以调试的严重错误。即使同步得到了正确的实现,我也会认为这种设计是脆弱的,因为它很容易被技术水平较低的维护程序员打破。
另一方面,如果DataTable中的Cache是只读的,我建议,与其将其与从数据库加载的数据进行比较,不如将其替换为来自数据库的数据--即定期刷新缓存。您的应用程序设计应该期望它有时会在缓存中找到不“新鲜”的数据。
https://stackoverflow.com/questions/7901897
复制相似问题