2016-11-18 8 views
0

Я ищу приложение Azure Mobile и настроил тестовый сервис и клиент.

Я настроить следующие Сущности сервис-сторона:

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 , DB заполняется, и я рад, что ключи/отношения настроены правильно. Я только с помощью соглашения об именовании 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 терпит неудачу с:

Сбой операции из-за конфликта: «Нарушение ограничения первичного ключа„PK_dbo.Hotels“. Невозможно вставить дубликат ключа в объект «dbo.Hotels». Дубликатное значение ключа (0e6e1bae-bd59-46ac-9630-a2b53dd04a90). \ R \ nПриложение завершено.

Но почему же он снова пытается включить мой дочерний объект INSERT? Во-первых, я не изменил его, а во-вторых, она имеет Id, CreatedAt и т.д.

я не могу найти какие-либо аналогичные вопросы, касающиеся Azure Mobile Apps, но я нашел this SO Post regarding Entity Framework но О.П. говорит о том, вручную создается детей, поэтому я не уверен, что он полностью применяется, поскольку я получил дочернюю сущность из БД через TableController.

+0

Я не знаком с Azure Mobile, но это выглядит как проблема с объектами, которые не имеют права «Entry.State» в контексте, те проблемы, которые возникают в отключенных сценариях. Похоже, что самый проголосовавший ответ в сообщении SO, на который вы ссылаетесь, исправит вашу проблему. Попробуйте установить дочерний элемент свойства 'aBooking.Hotel' в значение null перед выполнением' UpdateAsync' и оставить только значение «HotelId». – Diana

ответ

0

Azure Mobile Apps не поддерживает отношения. Вы сталкиваетесь с одним из многих вопросов, связанных с этим.

Если вы используете автономную синхронизацию, тогда разложите таблицы так, чтобы связь была менее необходимой, а затем синхронизируйте каждую таблицу отдельно.

Если вы не используете автономную синхронизацию, используйте специальный API для фиксации изменений в базе данных.

+0

Действительно? Мне бы хотелось посмотреть, где это задокументировано ... – OffHeGoes

+0

Я хотел бы также обратить ваше внимание на [это сообщение в блоге Microsoft об отношениях 1: n с помощью Mobile] (https://blogs.msdn.microsoft.com/ azuremobile/2014/06/18/insertupdate-данные с-1n-связь-с использованием внутрисетевого-бэкэнд-azuremobile-услуги /). – OffHeGoes

+0

Это сообщение в блоге о Azure Mobile Services, которое является предшественником для Azure Mobile Apps.Мы никогда не поддерживали отношения с Azure Mobile Apps. –