Правильный способ использования баз данных в Windows 8 и Windows Phone 8
В настоящее время я работаю над приложением для Windows 8, которое должно хранить некоторые таблицы. В настоящее время я использую XML-файлы с классами XDocument для решения этой задачи. Он использует save
и load
методы, использующие GetFileAsync
и CreateFileAsync
и т. д. Кроме того, существуют методы save
и load
, вызываемые различными событиями. Однако всякий раз, когда повторяются вызовы, выдается исключение, сообщающее мне, что доступ к файлу запрещен. Ожидаемое поведение - подробнее здесь ! Хотя есть грязные методы, чтобы этого избежать (например, использование замков и тому подобное) я не очень доволен результатами. Я бы предпочел базы данных. Кроме того, я планирую написать еще одно приложение для Windows Phone 8 (и, возможно, веб-версию), которое будет использовать эти данные.
Извините, если вопрос кажется неясным. Я предоставлю информацию, если потребуется.
5 ответов:
Если вы хотите использовать Azure, самый простой способ-это Windows Azure Mobile services. Он позволяет настроить базу данных и веб-сервисы с помощью веб-интерфейса в течение нескольких минут.
Это довольно круто, позволяет добавлять пользовательский javascript в логику веб-api и генерирует веб-API json. Существуют клиентские библиотеки для Windows 8, Windows Phone и iOS. Вы можете легко свернуть свой собственный для любых интерфейсов с поддержкой http.
Однако имейте в виду, что принимая облачный маршрут означает, что ваше приложение не будет работать в автономном режиме, (если вы не кодируете систему кэша, которая есть. А для кэширования потребуется локальная БД.)
О локальной БД Вы действительно должны это сделать.: 1) реальная БД в вашем приложении, как SQLite. Он доступен в виде пакетаNuget , но прямо сейчас поддержка ARM недоступна из коробки и не гарантируется командой. Если вам не нужна рука, попробуйте:)
2) обычное старое хранилище файлов, как и раньше. Лично я часто так делаю. Однако вы получите проблемы при доступе к нему из разных потоков (ошибки доступа запрещены).
Когда вы храните вещи в локальном файле, не забудьте заблокировать критические разделы (т. е. когда вы читаете или записываете в файл), чтобы предотвратить исключения, запрещенные для доступа. Чтобы быть уверенным, Инкапсулируйте свою логику записи / чтения в экземпляре класса обслуживания, уникальном в вашем приложении. (Используйте, например, синглетный шаблон или что-нибудь эквивалентное).
Теперь сам замок. Я полагаю, что вы используете асинхронный режим ждать. Мне тоже нравится эта сладкая штука. Но классические блокировки C# (например, с помощью ключевого слова
Вот почему в игру вступает чудесный AsyncLock. Это замок, но который - приблизительно-не блокирует (вы ждете его).lock
) не работают с async await. (И даже если бы это сработало, блокировка не была бы классной).public class AsyncLock { private readonly AsyncSemaphore m_semaphore; private readonly Task<Releaser> m_releaser; public AsyncLock() { m_semaphore = new AsyncSemaphore(1); m_releaser = Task.FromResult(new Releaser(this)); } public Task<Releaser> LockAsync() { var wait = m_semaphore.WaitAsync(); return wait.IsCompleted ? m_releaser : wait.ContinueWith((_, state) => new Releaser((AsyncLock)state), this, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } public struct Releaser : IDisposable { private readonly AsyncLock m_toRelease; internal Releaser(AsyncLock toRelease) { m_toRelease = toRelease; } public void Dispose() { if (m_toRelease != null) m_toRelease.m_semaphore.Release(); } } } public class AsyncSemaphore { private readonly static Task s_completed = Task.FromResult(true); private readonly Queue<TaskCompletionSource<bool>> m_waiters = new Queue<TaskCompletionSource<bool>>(); private int m_currentCount; public AsyncSemaphore(int initialCount) { if (initialCount < 0) throw new ArgumentOutOfRangeException("initialCount"); m_currentCount = initialCount; } public Task WaitAsync() { lock (m_waiters) { if (m_currentCount > 0) { --m_currentCount; return s_completed; } else { var waiter = new TaskCompletionSource<bool>(); m_waiters.Enqueue(waiter); return waiter.Task; } } } public void Release() { TaskCompletionSource<bool> toRelease = null; lock (m_waiters) { if (m_waiters.Count > 0) toRelease = m_waiters.Dequeue(); else ++m_currentCount; } if (toRelease != null) toRelease.SetResult(true); } }
Вы можете использовать его следующим образом (я полагаю, что у вас есть поле AsyncLock с именем blogLock (взято из одного из моих собственных проектов):
using (await blogLock.LockAsync()) { using (var stream = await folder.OpenStreamForReadAsync(_blogFileName)) { using (var reader = new StreamReader(stream)) { var json = await reader.ReadToEndAsync(); var blog = await JsonConvert.DeserializeObjectAsync<Blog>(json); return blog; } } }
Я наткнулся на эту тему, потому что у меня в основном та же самая проблема. Что кажется мне ошеломляющим, так это то, что Microsoft делает свой собственный продукт базы данных корпоративного класса (SQL Server), который уже имеет несколько легковесных, встраиваемых версий, и все же они, по-видимому, не могут быть использованы с приложениями Windows 8/Windows Phone 8 для обеспечения локальной базы данных. И все же MySQL может!
Я пытался пару раз баловаться написанием приложений для Windows Phone 8, используя мой ASP.NET/VB/NET/SQL опыт, но я всегда увязаю в попытках узнать другой способ выполнения операций с данными, которые я могу делать во сне в веб-среде, и теряю интерес. Почему они не могут упростить использование SQL с приложениями W8/WP8?
Если данные относятся к пользователю устройства, посмотрите на использование SQLlite ... есть вопрос по стеку о SQLlite и локальных базах данных winRT здесь: локальное хранилище баз данных для приложений WinRT / Metro
Я знаю, что это старый вопрос, на который уже есть приемлемый ответ, но я собираюсь вытащить свой мыльный ящик и ответить на него в любом случае, потому что я думаю, что вместо решения технической проблемы лучше использовать архитектуру, которая не зависит от локальных баз данных.
По моему опыту, очень мало данных требует локальных служб баз данных устройств.
Большинство пользовательских данных, требующих локального хранения, не являются перемещаемыми (т. е. специфичными для устройства) предпочтениями и конфигурацией пользователя (например, использовать съемный носитель настройки). Результаты игр попадают в эту категорию. Приложения, которые производят большие объемы пользовательских данных, обычно реализуются на рабочем столе и почти наверняка имеют быстрое надежное соединение с локальной сетью, что делает серверное хранилище в высшей степени подходящим даже для "жирных" данных, таких как офисные документы.
Справочные данные, безусловно, должны быть основаны на сервере,но вы можете выбрать кэширование. Nokia Maps на Windows Phone 8 является отличным примером кэширования серверные данные. Кэш может даже быть явно предварительно загружен в ожидании автономного использования.
Картина мира, которую я только что изложил, имеет мало пользы для локального SQL-сервера. Если вам нужен механизм запросов, используйте LINQ. Выразите Настройки Приложения и пользовательские данные в виде объектного графика и (de)сериализуйте XML. Вы даже можете использовать Linq2Xml непосредственно на XML, если вы не хотите поддерживать классы ORM.
Данные любого рода, которые должны быть доступны на всех устройствах пользователя на самом деле в любом случае его нужно хранить в облаке.
Чтобы обратиться к некоторым комментариям Акшая,
Картографические данные
Геопространственные данные обычно организуются в структуры, известные как Квадро-деревья, по целому ряду причин, в основном связанных с обеспечением уровня детализации, который изменяется с увеличением. То, как они доступны и управляются, получает значительное преимущество от их представления в виде объектных графов, и они не обновляются пользователями, так что, хотя эти данные, безусловно, могли бы быть хранится в реляционной базе данных, и это, вероятно, происходит во время компиляции, она, конечно, не хранится и не доставляется таким образом.LINQ хорошо адаптирован к этому сценарию, потому что он может быть применен непосредственно к квадродереву.
Данные, безусловно, находятся в файле. Но я полагаю, что вы имели в виду прямой доступ к файлу , а не косвенный через другой процесс. Вероятно, вы думаете, что это хорошая идея, чтобы вложить значительные усилия на тщательное решение проблемы. проблемы параллелизма и обработки запросов один раз и совместное решение между клиентскими приложениями. Но это очень тяжелое решение, и аспект обработки запросов уже хорошо обработан LINQ (именно поэтому я постоянно упоминаю об этом).
Ваши проблемы с XML
Только чтение не требует блокировки, поэтому избегайте проблемы блокировки файловой системы путем кэширования и использования Одноэлементного шаблона...
public static class XManager { static Dictionary<string, XDocument> __cache = new Dictionary<string, XDocument>(); public static XDocument GetXDoc(string filepath) { if (!__cache.Contains(filepath) { __cache[filepath] = new XDocument(); __cache[filepath].Load(filepath); } return _cache[filepath]; } }