我是实体框架的新手。我有一个保存货运数据的程序,我必须将该程序转换为实体框架功能。对于简单的插入/更新,我能够使用实体框架,但对于这个特定的程序,我面临着问题。
在下面的程序中,我必须更新具有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
答案 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);
}