在将存储过程转换为实体框架功能时面临问题

时间:2014-10-06 09:31:49

标签: c# entity-framework entity-framework-6

我是实体框架的新手。我有一个保存货运数据的程序,我必须将该程序转换为实体框架功能。对于简单的插入/更新,我能够使用实体框架,但对于这个特定的程序,我面临着问题。

在下面的程序中,我必须更新具有addressId,shipmenStatusId和serviceId作为外键的货件表。对于特定的货运记录,如果地址已经存在,则在外键列中添加现有地址ID,否则首先将新地址添加到地址表中,然后选择新地址ID并将其更新为货件地址id列,以及shippingStatusType和服务类型的相同步骤。 / p>

这是我的程序脚本。

CREATE PROCEDURE spSavePackage
@TrackingNbr VARCHAR(50),
@Carrier VARCHAR(10),
@PackageType VARCHAR(20) = NULL,
@ShippedDate DATETIME = NULL,
@ScheduledDate DATETIME = NULL,
@AddressLine1 VARCHAR(50)= NULL,
@AddressLine2 VARCHAR(50)= NULL,
@City VARCHAR(50) = NULL,
@State VARCHAR(2) = NULL,
@Country VARCHAR(2) = NULL,
@StatusDescription VARCHAR(50) = NULL 
AS

BEGIN

    DECLARE @AddressId int, @DeliveryStatusId int , @PackageId int

    IF EXISTS (SELECT Id FROM tblPackages WHERE TrackingNr = @TrackingNbr AND Carrier = @Carrier)
    BEGIN   
        IF EXISTS(SELECT Id FROM tblDeliveryAddress WHERE Address1 = @AddressLine1 AND Address2 = @AddressLine2
                    AND City = @City AND State = @State AND Country = @Country)
        BEGIN
            SELECT @AddressId = Id FROM tblDeliveryAddress WHERE Address1 = @AddressLine1 AND Address2 = @AddressLine2
                    AND City = @City AND State = @State AND Country = @Country
        END         
        ELSE            
        BEGIN
            SELECT @AddressId = MAX(Id) from tblDeliveryAddress
            SET @AddressId = @AddressId + 1

            INSERT INTO tblDeliveryAddress VALUES(@AddressId , @AddressLine1 , @AddressLine2 , @City , @State , @Country)   
        END

        IF EXISTS (SELECT Id FROM tblDeliveryStatus WHERE Status = @StatusDescription)
        BEGIN
            SELECT @DeliveryStatusId = Id FROM tblDeliveryStatus WHERE Status = @StatusDescription
        END
        ELSE
        BEGIN
            SELECT @DeliveryStatusId = MAX(Id) FROM tblDeliveryStatus
            SET @DeliveryStatusId = @DeliveryStatusId + 1

            INSERT INTO tblDeliveryStatus VALUES(@DeliveryStatusId , @StatusDescription)
        END

        UPDATE tblPackages
        SET DeliveryAddressID = @AddressId, DeliveryStatusId = @DeliveryStatusId,
        ShippedDate = @ShippedDate , PackageType = @PackageType, ScheduledDate = @ScheduledDate
        WHERE TrackingNr = @TrackingNbr AND Carrier = @Carrier
    END
    ELSE
    BEGIN
        SELECT @PackageId = MAX(Id) FROM tblPackages
        SET @PackageId = @PackageId + 1
        INSERT INTO tblPackages(Id , TrackingNr , Carrier) VALUES (@PackageId , @TrackingNbr , @Carrier)
    END 
END 

为了实现这个过程的功能,我创建了以下EF代码。

public void UpdateShipments(List<Tuple<tblShipment, List<tblActivity>>> shipments)
    {
        tblShipment shipment = null;
        var manager = ((IObjectContextAdapter)this._context).ObjectContext.ObjectStateManager;
        foreach (var tuple in shipments)
        {
            shipment = tuple.Item1;

            if (shipment.ConsigneeAddress != null)
            {
                shipment.ConsigneeAddressId = this.AddAddress(shipment.ConsigneeAddress).ID;
                shipment.ConsigneeAddress = null;
            }
            else
            {
                shipment.ConsigneeAddressId = null;
                shipment.ConsigneeAddress = null;
            }

            if (shipment.ShipperAddress != null)
            {
                shipment.ShipperAddressId = this.AddAddress(shipment.ShipperAddress).ID;
                shipment.ShipperAddress = null;
            }
            else
            {
                shipment.ShipperAddressId = null;
                shipment.ShipperAddress = null;
            }

            if (shipment.Service != null)
            {
                shipment.ServiceId = this.AddService(shipment.Service).ID;
                shipment.Service = null;
            }
            else
            {
                shipment.ServiceId = null;
                shipment.Service = null;
            }

            if (shipment.ShipmentStatusType != null)
            {
                shipment.ShipmentStatusId = this.AddStatusType(shipment.ShipmentStatusType).ID;
                shipment.ShipmentStatusType = null;
            }
            else
            {
                shipment.ShipmentStatusId = null;
                shipment.ShipmentStatusType = null;
            }

            this._context.Entry(shipment).State = System.Data.Entity.EntityState.Modified;
        }
        this._context.SaveChanges();
    }


public tblAddressType AddAddressType(tblAddressType addressType)
    {
        tblAddressType tempAddressType = (from m in this._context.AddressTypes
                                          where m.Type.ToUpper() == addressType.Type.ToUpper()
                                          select m).FirstOrDefault();
        if (tempAddressType == null)
        {
            tempAddressType = this._context.AddressTypes.Add(addressType);
            this._context.SaveChanges();
        }

        return tempAddressType;
    }

    public tblAddress AddAddress(tblAddress address)
    {
        tblAddress tempAddress = (from m in this._context.Addresses
                                  where m.AddressLine1.ToUpper() == address.AddressLine1.ToUpper() && m.AddressLine2.ToUpper() == address.AddressLine2.ToUpper() && m.City.ToUpper() == address.City.ToUpper()
                       && m.StateProvinceCode.ToUpper() == address.StateProvinceCode.ToUpper() && m.CountryCode.ToUpper() == address.CountryCode.ToUpper()
                                  select m).FirstOrDefault();

        if (tempAddress == null)
        {
            address.AddressType = this.AddAddressType(address.AddressType);
            address.AddressTypeId = address.AddressType.ID;
            address.AddressType = null;
            tempAddress = this._context.Addresses.Add(address);
            this._context.SaveChanges();
        }

        return tempAddress;
    }

花了很多时间后我发现这种方式来实现它但我不满意这个实现。因为我必须为保存/更新装运记录做很多工作,这会减慢流程。我需要一些优化的方式来更新货件记录,以便保存记录我只需要单个数据库命中。我有多个货运记录(收集的记录),我希望单个数据库命中保存记录或1个数据库命中以保存一个货件记录。

我试图澄清我的问题,如果任何一个面临问题理解它然后让我知道。我使用c#作为编程语言,sql server作为数据库,实体框架6.0作为ORM。

任何帮助将不胜感激。

谢谢, Awadhendra

1 个答案:

答案 0 :(得分:0)

过去我遇到过类似的问题。 虽然由于硬编码可能会改变的东西,它可能会被其他人认为是黑客攻击,如果你还实现了简单的集成测试(稍后见一个例子),就可以跟踪这些变化

这是我的解决方案

namespace ContextNamespace
{
    public partial class ContextClass
    {
      public Task UpdateShipments(List<Tuple<tblShipment,
                                        List<tblActivity>>> shipments)
      {
        return this.Database.ExecuteSqlCommandAsync("EXEC spSavePackage @p1 = @p1..", 
               new SqlParameter("@p1", shipments.???),....);
       }
    }
}

除此之外,我还有像这样的集成测试,他们的目的只是通过而无例外 - 当然,他们可以很容易地充实以包含更多适当的检查

    [TestMethod]
    public async Task Sproc_Test()
    {
        //Create object
        Context context = new Context();
        await context.UpdateShipments(/*object*/);
    }

在代码中使用的一个例子是这样的

 public Task DoSomething(Object data)
 {
     return Context.UpdateShipments(data);
 }