为什么在我的实体框架中添加一个子元素会尝试插入一个新的父元素

本文关键字:一个 元素 插入 框架 实体 为什么 我的 添加 | 更新日期: 2023-09-27 18:29:23

我在WCF中有一个C#REST服务,它位于SQL 2008上的EF 4.2框架之上。有几个实体,但重要的两个是Trips和他们的孩子PlacesOfInterest。

以下是表格:

-- Creating table 'Trips'
CREATE TABLE [dbo].[Trips] (
[Id] uniqueidentifier  NOT NULL,
[Name] nvarchar(max)  NOT NULL,
[ArrivalDate] datetime  NULL,
[DepartureDate] datetime  NULL,
[WhereTo] nvarchar(max)  NOT NULL,
[CreatedDate] datetime  NULL,
[UpdatedDate] datetime  NULL,
[Album] nvarchar(max)  NOT NULL,
[UserToken] nvarchar(max)  NOT NULL,
[WallPostId] nvarchar(max)  NOT NULL
);
GO
-- Creating table 'PlacesOfInterest'
CREATE TABLE [dbo].[PlacesOfInterest] (
[Id] uniqueidentifier  NOT NULL,
[PhoneNumber] nvarchar(max)  NOT NULL,
[SmallPicture] nvarchar(max)  NOT NULL,
[LargePicture] nvarchar(max)  NOT NULL,
[HostId] nvarchar(max)  NOT NULL,
[HostName] nvarchar(max)  NOT NULL,
[Address1] nvarchar(max)  NOT NULL,
[Address2] nvarchar(max)  NOT NULL,
[Address3] nvarchar(max)  NOT NULL,
[City] nvarchar(max)  NOT NULL,
[State] nvarchar(max)  NOT NULL,
[Zip] nvarchar(max)  NOT NULL,
[Latitude] bigint  NOT NULL,
[Longitude] bigint  NOT NULL,
[URL] nvarchar(max)  NOT NULL,
[MapUrl] nvarchar(max)  NOT NULL,
[Hours] nvarchar(max)  NOT NULL,
[Name] nvarchar(max)  NOT NULL,
[PageId] nvarchar(max)  NOT NULL,
[Trip_Id] uniqueidentifier  NOT NULL,
[Category_Id] int  NULL
);
GO

这是我的POCO模型。

public class Trip
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public DateTime ArrivalDate { get; set; }
    public DateTime DepartureDate { get; set; }
    public string WhereTo { get; set; }
    public DateTime CreatedDate { get; set; }
    public DateTime UpdatedDate { get; set; }
    public string Album { get; set; }
    public List<PlaceOfInterest> PlacesOfInterest { get; set; }
    public List<Photo> Photos { get; set; }
    public string UserToken { get; set; }
    public string WallPostId { get; set; }
}
public class PlaceOfInterest
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string PhoneNumber { get; set; }
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string Address3 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Zip { get; set; }
    public long Latitude { get; set; }
    public long Longitude { get; set; }
    public string SmallPicture { get; set; }
    public string LargePicture { get; set; }
    public string HostId { get; set; }
    public string HostName { get; set; }
    public string URL { get; set; }
    public string MapUrl { get; set; }
    public string Hours { get; set; }
    public Category Category { get; set; }
    public List<Photo> Photos { get; set; }
    public List<Checkin> Checkins { get; set; }
    public List<PoiAttribute> PoiAttributes { get; set; }
    public Guid TripId { get; set; }
    public string PageId { get; set; }
    [IgnoreDataMember]
    public Trip Trip { get; set; }
}

当我添加一个新的PlaceOfInterest时,实体框架试图插入一个列表,但我得到了一个重复的键错误。

    public static Guid Create(string tripId, Model.PlaceOfInterest instance)
    {
        var context = new Model.POCOTripContext();
        var cleanPoi = new Model.PlaceOfInterest();
        cleanPoi.Id = Guid.NewGuid();
        cleanPoi.Address1 = instance.Address1;
        cleanPoi.Address2 = instance.Address2;
        cleanPoi.Address3 = instance.Address3;
        cleanPoi.City = instance.City;
        cleanPoi.HostId = instance.HostId;
        cleanPoi.HostName = instance.HostName;
        cleanPoi.Hours = instance.Hours;
        cleanPoi.LargePicture = instance.LargePicture;
        cleanPoi.Latitude = instance.Latitude;
        cleanPoi.Longitude = instance.Longitude;
        cleanPoi.MapUrl = instance.MapUrl;
        cleanPoi.Name = instance.Name;
        cleanPoi.PageId = instance.PageId;
        cleanPoi.PhoneNumber = instance.PhoneNumber;
        cleanPoi.SmallPicture = instance.PhoneNumber;
        cleanPoi.State = instance.State;
        cleanPoi.Trip = Library.Trip.Get(new Guid(tripId));
        cleanPoi.URL = instance.URL;
        cleanPoi.Zip = instance.Zip;
        context.PlacesOfInterest.AddObject(cleanPoi);
        context.SaveChanges();
        return cleanPoi.Id;
    }

我不希望它插入那个行程,我只希望它更新数据库中的TripId列。我做错了什么?

为什么在我的实体框架中添加一个子元素会尝试插入一个新的父元素

很可能这一行就是问题所在:

cleanPoi.Trip = Library.Trip.Get(new Guid(tripId))

如果Get从DB加载跳闸,那么它显然是在context之外的另一个上下文中加载的。您应该使用相同的上下文。为了把它写得难看,比如:Get(context, new Guid(tripId)),然后使用注入的上下文。

如果Get只创建了Tripnew Trip { ... })的实例,则必须将其附加到上下文:

cleanPoi.Trip = Library.Trip.Get(new Guid(tripId))
context.Trips.Attach(cleanPoi.Trip);

但你们都不需要,因为你们显然有一个外国的关键财产。那么这就足够了:

cleanPoi.TripId = new Guid(tripId);

您应该从正在保存的同一DataContext中获取cleanPoi.Trip。

在您的Create方法中,您将获得Trip并将PointOfInterest的Trip设置为您捕获的Trip。这有两个问题:

  1. 您没有处理Trip不存在的情况
  2. 您正在设置对Trip的引用,该引用正被DbContext中的ChangeTracker捕获

您可以通过简单地在PointOfInterest对象上设置TripId来解决这两个问题,然后将整个事情封装在Try/Catch中,该Try/Catck处理EF在外键不存在时将抛出的异常。

此外,您还需要深入了解InnerException的详细信息,因为返回的Exception将有非常具体的问题信息。问题可能是其中一个Guid=Guid.Empty,而您正在插入的Guid也为空。这将证明一个完全不同的问题。