首页 > 解决方案 > EF Core 3.x:重复值

问题描述

我有以下代码:

public class DeviceVerizon
{
    public int DeviceId { get; set; }
    public string InternalDeviceId { get; set; }
}

public class DeviceVerizonMap : IEntityTypeConfiguration<DeviceVerizon>
{
    public void Configure(EntityTypeBuilder<DeviceVerizon> builder)
    {
        builder.ToTable(nameof(DeviceVerizon));
        builder.HasKey(d => d.DeviceId);

        builder.HasIndex(v => v.InternalDeviceId).IsUnique();

        builder.HasOne(o => o.Device)
            .WithOne(o => o.VerizonData)
            .HasForeignKey<DeviceVerizon>(a => a.DeviceId)
            .OnDelete(DeleteBehavior.Cascade)
            .IsRequired()
            ;
    }
}

所以,InternalDeviceId 只是唯一索引。

一些代码更改现有记录的 InternalDeviceId 并使用以前的 InternalDeviceId 添加新记录。所以,localDevice.VerizonData.InternalDeviceId = 1420531689

我将其更新为新的 ( remoteDevice.VerizonData.InternalDeviceId = '111111111')

                localDevice.VerizonData = remoteDevice.VerizonData;
                _context.Devices.Update(localDevice);

然后添加新记录remoteDevice.VerizonData.InternalDeviceId = 1420531689

                _context.Devices.Add(remoteDevice);

之后我打电话:

    await _context.SaveChangesAsync();

但我得到一个例外:

无法在具有唯一索引“IX_DeviceVerizon_InternalDeviceId”的对象“dbo.DeviceVerizon”中插入重复的键行。重复键值为 (1420531689)。

完整代码:

    foreach (var remoteDevice in remoteVerizonDevices)
    {
        var localDevice = allLocalDevicesWithIMEI.Where(a => 
            (string.IsNullOrWhiteSpace(remoteDevice.IMEI) 
            && a.VerizonData != null 
            && a.VerizonData.InternalDeviceId == remoteDevice.VerizonData.InternalDeviceId 
            && a.IMSI == remoteDevice.IMSI && a.ICCID == remoteDevice.ICCID) 
            || a.IMEI == remoteDevice.IMEI).FirstOrDefault();

        if (localDevice != null) // device with such imei already exists or IMEI is empty on Verizon, but InternalDeviceId is the same and ICCID with IMSI are the same
        {
            var verizonStatus = remoteDevice.VerizonData.State.ConvertToDeviceStatusFromVerizonStatus();

            var existingRequest = _context.VerizonRequests.Where(a => a.DeviceId == localDevice.Id && a.Result == VerizonRequestResult.Pending).FirstOrDefault();

            if (verizonStatus == DeviceStatus.Active && remoteDevice.IsVerizonLastActiveMoreThanDays(60))
            {
                // existing request for this device does not exist, create new
                if (existingRequest == null)
                {
                    localDevice.Status = DeviceStatus.PendingSuspend;
                    localDevice.DateStatusChanging = DateTime.UtcNow;
                    localDevice.LastStatusChangeSource = DeviceStatusChangeSource.Verizon;
                    // create verizon request to change status, because device is offline more than 60 days
                    verizonSuspensionList.Add(localDevice.Id);
                }
            }
            else
            {
                // Is Verizon status of device is different than locally?
                if (localDevice.Status != verizonStatus)
                {
                    // check whether we have active verizon request, if not, then
                    if (existingRequest == null)
                    {
                        // device is suspended on suremdm, we should suspend on Verizon
                        if (localDevice.Status == DeviceStatus.Suspended
                            && verizonStatus == DeviceStatus.Active)
                        {
                            if (localDevice.Tablet != null && localDevice.Tablet.TabletGroup.GroupName == SpecialSureMdmGroups.Suspended)
                                verizonSuspensionList.Add(localDevice.Id);
                        }
                        else if (localDevice.Status != DeviceStatus.Suspended && verizonStatus == DeviceStatus.Suspended)
                        {
                            // if device is suspended on verizon, we need to suspend on SureMdm
                            localDevice.Status = DeviceStatus.PendingSuspend;
                            localDevice.DateStatusChanging = DateTime.UtcNow;
                            localDevice.LastStatusChangeSource = DeviceStatusChangeSource.Verizon;
                            if (localDevice.Tablet != null)
                            {
                                localDevice.Tablet.SuspensionDate = DateTime.UtcNow;

                                sureMdmSuspensionList.Add(new Core.Dto.DeviceManagement.SureMdm.SureMdmMoveDeviceToSuspendedGroupDto
                                {
                                    TabletId = localDevice.Tablet.TabletId,
                                    CurrentGroupId = localDevice.Tablet.TabletGroupId
                                });
                            }
                        }
                        else
                        {
                            // other cases that device on verizon has different status, that locally
                            VerizonStatusIsDifferentEvent?.Invoke(
                                remoteDevice: remoteDevice,
                                verizonStatus: remoteDevice.VerizonData.State.ConvertToDeviceStatusFromVerizonStatus(),
                                localStatus: localDevice.Status);
                        }
                    }
                }
            }

            var changes = DeviceIsChanged(remoteDevice, localDevice);
            if (changes != null && changes.Count > 0)
                modifiedDevices.Add((localDevice, changes));

            var continueToUpdate = true;

            // if verizon data does not exist, add it
            if (localDevice.VerizonData == null)
            {
                var existingInternalVerizonDeviceIdRecord = allDeviceVerizons.Where(a => a.InternalDeviceId == remoteDevice.VerizonData.InternalDeviceId).FirstOrDefault();
                if (existingInternalVerizonDeviceIdRecord != null)
                {
                    DeviceWithTheSameVerizonDeviceIdAlreadyExistsEvent?.Invoke(remoteDevice: remoteDevice,
                        localDevice: existingInternalVerizonDeviceIdRecord.Device,
                        verizonDeviceId: remoteDevice.VerizonData.InternalDeviceId);
                    continueToUpdate = false;
                }
            }

            if (continueToUpdate)
            {
                localDevice.VerizonData = remoteDevice.VerizonData;

                if (!string.IsNullOrWhiteSpace(remoteDevice.ICCID))
                    localDevice.ICCID = remoteDevice.ICCID;
                localDevice.EID = remoteDevice.EID;
                localDevice.ESN = remoteDevice.ESN;
                if (!string.IsNullOrWhiteSpace(remoteDevice.IMSI))
                    localDevice.IMSI = remoteDevice.IMSI;
                if (!string.IsNullOrWhiteSpace(remoteDevice.MDN))
                    localDevice.MDN = remoteDevice.MDN;
                localDevice.MEID = remoteDevice.MEID;
                localDevice.MIN = remoteDevice.MIN;
                localDevice.MSISDN = remoteDevice.MSISDN;
                localDevice.SKU = remoteDevice.SKU;
                localDevice.SyncVerizon = true;

                if (string.IsNullOrWhiteSpace(localDevice.Name))
                    localDevice.Name = localDevice.IMEI;

                if (!localDevice.DeviceModelId.HasValue)
                {
                    var verizonGroup = allVerizonGroups.Where(a => a.VerizonGroupName == remoteDevice.VerizonData.GroupName).FirstOrDefault();
                    if (!verizonGroup.DeviceModelId.HasValue)
                        VerizonGroupIsNotLinkedWithDeviceModelEvent?.Invoke(remoteDevice);
                    else
                        localDevice.DeviceModelId = verizonGroup.DeviceModelId;
                }

                _context.Devices.Update(localDevice);
            }
        }
        else
        {
            // validate by Internal Verizon DeviceId
            var existingInternalVerizonDeviceIdRecord = allDeviceVerizons.Where(a => a.InternalDeviceId == remoteDevice.VerizonData.InternalDeviceId).FirstOrDefault();
            if (existingInternalVerizonDeviceIdRecord != null)
            {
                DeviceWithTheSameVerizonDeviceIdAlreadyExistsEvent?.Invoke(remoteDevice: remoteDevice,
                    localDevice: existingInternalVerizonDeviceIdRecord.Device,
                    verizonDeviceId: remoteDevice.VerizonData.InternalDeviceId);
            }
            else
            {
                // add new record
                if (!string.IsNullOrWhiteSpace(remoteDevice.IMEI))
                    remoteDevice.Name = remoteDevice.IMEI;
                else if (!string.IsNullOrWhiteSpace(remoteDevice.VerizonData.PrimaryPlaceOfUseFirstName) || !string.IsNullOrWhiteSpace(remoteDevice.VerizonData.PrimaryPlaceOfUseLastName))
                    remoteDevice.Name = $"{remoteDevice.VerizonData.PrimaryPlaceOfUseFirstName} {remoteDevice.VerizonData.PrimaryPlaceOfUseLastName}";
                else
                    remoteDevice.Name = Core.Constants.Common.Undefined;

                // set device Model
                var verizonGroup = allVerizonGroups.Where(a => a.VerizonGroupName == remoteDevice.VerizonData.GroupName).FirstOrDefault();
                if (!verizonGroup.DeviceModelId.HasValue)
                    VerizonGroupIsNotLinkedWithDeviceModelEvent?.Invoke(remoteDevice);
                else
                    remoteDevice.DeviceModelId = verizonGroup.DeviceModelId;

                // set device status
                remoteDevice.Status = remoteDevice.VerizonData.State.ConvertToDeviceStatusFromVerizonStatus();

                if (!string.IsNullOrWhiteSpace(remoteDevice.VerizonData.CarrierName))
                {
                    var verizonCarrier = allVerizonCarriers.Where(a => a.VerizonCarrierName == remoteDevice.VerizonData.CarrierName).FirstOrDefault();
                    if (verizonCarrier.CarrierId.HasValue)
                        remoteDevice.CarrierId = verizonCarrier.CarrierId;
                    else
                    {
                        // notify that carrier is not found locally
                        LocalCarrierIsNotFoundForNewDeviceEvent?.Invoke(remoteDevice);
                    }
                }

                remoteDevice.SyncVerizon = true;

                _context.Devices.Add(remoteDevice);
                newDevices.Add(remoteDevice);
            }
        }
    }

    await _context.SaveChangesAsync();

为什么这样?只有一条记录有 1420531689,旧的已更新为新值(111111111)并保存在一个事务中......如何正确执行?

标签: entity-frameworkentity-framework-coreef-core-3.1

解决方案


推荐阅读