Azure移动应用程序 - 实体框架尝试重新插入子项时出错 - 使用$ expand时

时间:2016-11-18 12:42:51

标签: c# entity-framework odata azure-mobile-services

我正在研究Azure移动应用程序并设置了测试服务和客户端。

我已设置以下实体服务端:

public class Hotel : EntityData
{
    public string Title { get; set; }

    public virtual ICollection<Booking> Bookings { get; set; }
}

public class Booking : EntityData
{
    public BookingStatus BookingStatus { get; set; }

    [ForeignKey("PersonId")]
    public virtual Person Person { get; set; }

    [ForeignKey("HotelId")]
    public virtual Hotel Hotel { get; set; }

    public string PersonId { get; set; }

    public string HotelId { get; set; }
}

public class Person : EntityData
{
    public string Name { get; set; }

    public virtual ICollection<Booking> Bookings { get; set; }
}

控制器:

public class BookingController : TableController<Booking>
{
    protected override void Initialize(HttpControllerContext controllerContext)
    {
        base.Initialize(controllerContext);
        MobileServiceContext context = new MobileServiceContext();
        DomainManager = new EntityDomainManager<Booking>(context, Request);
    }

    // GET tables/Booking/48D68C86-6EA6-4C25-AA33-223FC9A27959
    public SingleResult<Booking> GetBooking(string id)
    {
        return Lookup(id);
    }

    // GET tables/Booking
    public IQueryable<Booking> GetAllBookings()
    {
        return Query();
    }

    // PATCH tables/Booking/48D68C86-6EA6-4C25-AA33-223FC9A27959
    public Task<Booking> PatchBooking(string id, Delta<Booking> patch)
    {
        return UpdateAsync(id, patch);
    }
}

我使用CreateDatabaseIfNotExists<MobileServiceContext>添加了一些默认数据,当我启动并测试Web API时,数据库会被填充,我很高兴能够正确设置密钥/关系。我只是使用Code First约定命名(根据this tutorial

我还创建了一个包含以下实体的测试客户端:

public class Person
{
    public string Id { get; set; }
    public byte[] Version { get; set; }

    public string Name { get; set; }
    public virtual ICollection<Booking> Bookings { get; set; }
}

public class Booking
{
    public string Id { get; set; }
    public byte[] Version { get; set; }

    public BookingStatus BookingStatus { get; set; }
    public string PersonId { get; set; }
    public string HotelId { get; set; }        
    public virtual Person Person { get; set; }
    public virtual Hotel Hotel { get; set; }
}

public class Hotel
{
    public string Id { get; set; }
    public byte[] Version { get; set; }

    public string Title { get; set; }
    public virtual ICollection<Booking> Bookings { get; set; }
}

使用此测试逻辑:

using (var client = new MobileServiceClient(m_Url, new ODataParameterHandler())
{
    client.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
    client.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;

    var bookingTable = client.GetTable<Booking>();
    var bookings = await placementTable
                .Where(p => p.BookingStatus == BookingStatus.Confirmed && p.PersonId == 10)
                .WithParameters(new Dictionary<string, string> { { "expand", "Hotel" } })
                .ToListAsync();

    var aBooking = bookings[0];     
    aBooking.BookingStatus = BookingStatus.Cancelled;

    await bookingTable.UpdateAsync(aBooking);
}

// Class to allow $expand= querystring value to be passed in.
public class ODataParameterHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        UriBuilder builder = new UriBuilder(request.RequestUri);

        builder.Query = builder.Query
            .Replace("expand", "$expand")
            .TrimStart('?');

        request.RequestUri = builder.Uri;

        return await base.SendAsync(request, cancellationToken);
    }
}

GET / ToListAsync正常工作,我将Hotel对象附加到我的Booking。但是,Update失败了:

  

由于冲突导致操作失败:&#39;违反PRIMARY KEY约束&#39; PK_dbo.Hotels&#39;。无法在对象&#39; dbo.Hotels&#39;中插入重复的密钥。重复键值为(0e6e1bae-bd59-46ac-9630-a2b53dd04a90)。\ r \ n语句已终止。

但是为什么要再次插入我的孩子对象?首先,我没有改变它,其次,它有一个Id,{{1等等。

我找不到任何有关Azure移动应用程序的类似问题,但我确实找到了this SO Post regarding Entity Framework但是OP谈到了手动创建子项,因此我不确定它是否完全适用,因为我从中获取了子实体数据库通过CreatedAt

1 个答案:

答案 0 :(得分:0)

Azure移动应用不支持关系。你正在碰到与之相关的众多问题之一。

如果您正在使用离线同步,那么请对表进行分解,以便不再需要链接,然后单独同步每个表。

如果您没有使用离线同步,请使用自定义API将更改提交到数据库。