首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何获得除添加IEnumerable之外引起的差异?

如何获得除添加IEnumerable之外引起的差异?
EN

Stack Overflow用户
提问于 2011-10-26 11:20:38
回答 3查看 114关注 0票数 1

我使用Enumerable.Except检查内存中的DataTable是否与数据库中的表同步。

背景是:这个DataTable和其他经常使用的表存储在WebApplication的Cache中。但同时,我确信这不是一个好方法,因为它是一个很难再现/调试的严重错误的来源。

因此,我创建了一个函数来检查数据库和内存是否同步,否则将创建一个错误日志。这工作得很好。如果内存中有一行不在数据库中,这一行将显示在“数据库中的差异”下面,同样的情况也适用于相反的情况。但是,如果两个数据源( PK idRMA)中都存在行,并且某些值不同,则日志将包含两个版本的该行(在“数据库中的差异”和“数据库中的差异”下面)。一见钟情是不容易看出的。

Q:是否可以只选择导致Except认为第一个序列不在第二个序列的属性?

这是完整的函数(第一行是相关的):

代码语言:javascript
复制
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 Sub

Note:我可以比较所有的属性,但是我想知道是否有一种更简单的(LINQ)方法。基本上,我在寻找一种LINQ方法,只获取两种匿名类型序列的差异(因为我只选择DataRow的相关列来进行比较)。

编辑:我假设我必须在主键(idRMA)上加入这两者,但是我如何选择这些差异呢?如果联接不返回结果,则ID在第二个序列中不存在,并且可以记录所有属性。但是,如果在第二个序列中有一个适当的记录,我如何选择不同的属性?

代码语言:javascript
复制
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` '
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-10-26 13:15:11

只要没有人知道更好的方法,我就会坚持笨拙的做法。只需再次比较它们,只显示不同的值,否则“相等”。

代码语言:javascript
复制
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

产生以下示例性输出:

代码语言:javascript
复制
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)中启动应用程序,并删除/创建一些测试记录,或者到处更改一些值。

票数 0
EN

Stack Overflow用户

发布于 2011-10-26 11:30:25

我认为您需要像描述的这里那样创建一个自定义的相等比较器。最终,您将不得不以某种方式比较属性值,并且由于您使用的是Except(),所以您可以保持事物的一致性,并创建一个自定义比较器。

除此之外,您还可以编写一个单独的函数来为您完成这项工作。重要的是你喜欢什么。

编辑:

这是非常粗略的代码,但希望可以帮助您:

代码语言:javascript
复制
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; }

    }

我不是一个反射专家,所以如果别人可以评论我的代码,那就太好了。

最后,我不确定缓存数据是否是这里最好的方法。您可能需要考虑将信息存储在数据库中。缓存的问题是,在任何时候,该网站可能被回收(或重新启动),您可以松散您的内存数据。

在数据库中拥有数据的另一个优点是,您可以直接在数据库上运行查询,以便知道哪些属性已经更改。在您的角度下,这就是我要做的-在数据库中创建一个表来存储您在缓存中拥有的信息。

票数 2
EN

Stack Overflow用户

发布于 2011-10-26 11:42:01

这不是在回答你的问题,所以如果它没有帮助的话,就放弃吧,但是你可能想要更多地思考你的设计。

此DataTable和其他常用表存储在WebApplication的缓存中。但同时,我确信这不是一个好方法,因为它是一个很难再现/调试的严重错误的来源。

这是红旗。DataTable不是线程安全的,所以您可能永远不应该修改Cache中的线程安全。如果不进行同步,肯定会给您带来难以调试的严重错误。即使同步得到了正确的实现,我也会认为这种设计是脆弱的,因为它很容易被技术水平较低的维护程序员打破。

另一方面,如果DataTable中的Cache是只读的,我建议,与其将其与从数据库加载的数据进行比较,不如将其替换为来自数据库的数据--即定期刷新缓存。您的应用程序设计应该期望它有时会在缓存中找到不“新鲜”的数据。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/7901897

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档