【问题标题】:Why does adding a child element to my entity framework try and insert a new parent?为什么向我的实体框架添加子元素会尝试插入新的父元素?
【发布时间】:2012-03-28 20:33:38
【问题描述】:

我在 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 列。我做错了什么?

【问题讨论】:

    标签: c# wcf entity-framework rest poco


    【解决方案1】:

    这行很可能是问题所在:

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

    如果Get 从数据库加载行程,那么它显然是在context 之外的另一个上下文中加载它。您应该使用相同的上下文。写得很丑,比如:Get(context, new Guid(tripId)),然后使用注入的上下文。

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

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

    但是你们都不需要那个,因为你们显然有一个外键属性。那么这就足够了:

    cleanPoi.TripId = new Guid(tripId);
    

    【讨论】:

    • 这个context.PlacesOfInterest.Attach(cleanPoi.Trip);不应该是context.Trips.Attach(cleanPoi.Trip);吗?
    • 这行得通,但是当我到达 SaveChanges 时,数据库插入炸弹:{"无法将值 NULL 插入列 'Id',表 'PersonalAssistant.dbo.PlacesOfInterest';列不允许nulls。INSERT 失败。\r\n语句已终止。"} ID 字段填充在 cleanPoi 和上下文对象中。想法?
    • @BillSempf:您是否为Id 列设置了DatabaseGeneratedOption.Identity?在 Fluent API 中还是作为数据注释?如果没有,我不知道。也许问一个新问题。这很奇怪,因为对于 Guid 键,DatabaseGeneratedOption.None 是默认值,这意味着 EF 应该将 Id 值发送到数据库并且不应发生此异常。
    • 在最后一组 EF 更改后我没有更新我的数据库 - 我的错。感谢您的帮助!
    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      在您的 Create 方法中,您将获取 Trip 并将 PointOfInterest 的 Trip 设置为您抓取的那个行程。这有两个问题:

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-25
        • 2019-01-08
        • 1970-01-01
        • 2019-07-07
        • 2021-03-06
        • 2013-10-31
        相关资源
        最近更新 更多