在Windows 8和Windows Phone 8中正确使用数据库的方法

4
我正在开发一个需要存储一些表格的Windows 8应用程序。目前,我正在使用XML文件和XDocument类来解决这个问题。它采用了saveload方法,使用GetFileAsyncCreateFileAsync等方法。此外,saveload方法通过不同的事件调用。但是,每当有重复调用时,就会抛出异常,告诉我文件访问被拒绝。期望的行为- 在此处获取更多详细信息!尽管有一些不太好的方法可以避免这种情况(例如使用锁等),但我对结果并不满意。我更喜欢数据库。此外,我计划编写另一个适用于Windows Phone 8(可能还有Web版本)的应用程序,该应用程序将利用这些数据。
他们一直说Windows 8是基于云的。现在的问题是:存储数据的正确方式是什么?XML似乎是正确的,但是存在上述问题。在涉及Windows 8、Windows Phone 8和可能的Azure时,什么是理想的基于云的解决方案?我只想存储表格并使其可访问。
5个回答

7
如果您想使用Azure,最简单的方法是使用Windows Azure移动服务。它允许您在几分钟内使用Web界面设置数据库和Web服务。
这很酷,允许您向您的Web API逻辑添加自定义JavaScript,并生成JSON Web API。有Windows 8、Windows Phone和iOS的客户端库。您可以轻松地为任何启用HTTP的前端编写自己的。
但是请注意,选择云路线意味着您的应用程序将无法脱机工作(如果您不编写缓存系统的话。而缓存需要本地DB)。
关于本地DB: 您真的有两种可能性: 1)在应用程序中使用真正的DB,如SQLite。它作为Nuget包可用,但现在ARM支持不是开箱即用的,也不被团队保证。如果您不需要ARM,请尝试一下:)
2)像以前一样使用普通的文件存储。我个人经常这样做。但是当从不同的线程访问它时会遇到问题(Access Denied错误)。
当您将东西存储在本地文件中时,请不要忘记锁定关键部分(即在读取或写入文件时)以防止访问被拒绝的异常。为了确保,将您的写入/读取逻辑封装在应用程序中唯一的服务类实例中。(例如使用单例模式或任何等效方法)。
现在是锁本身。我想您正在使用async await。我也喜欢这个甜蜜的东西。但是经典的C#锁(例如使用lock关键字)不与async await一起使用。(即使它可以工作,阻塞也不酷)。
这就是神奇的AsyncLock发挥作用的原因。这是一个锁,但是-大致上-不会阻塞(您等待它)。
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);

    }
}

您可以这样使用它(假设您有一个名为blogLock的AsyncLock字段(来自我自己的项目之一):

            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;
                    }
                }
            }

我之前也有类似的想法。然而,对于孩子们来说整个事情似乎有些令人生畏。让我来分解一下!我想我会自己弄清楚数据库部分。接下来你提到(“相当酷”的事情)“Web API和Javascript逻辑”——详细介绍会很有帮助。最后,关于缓存部分!有什么好方法吗?我们是从服务器获取数据并将其存储在特定平台的本地数据库中吗? - akshay2000
好的,我会给你一个详细的答案。但是你能多说一些关于你的应用程序吗? - Eilistraee
1
这真的取决于您的应用逻辑和期望的合并算法。如果客户端无法更改数据,则很容易。将其缓存,并在有网络连接时刷新缓存。如果客户端可以更改数据,则可以使用时间戳进行合并,但是例如,如果客户端A在时间戳1获取数据,在时间3更改数据,并在尝试将更改推送到服务器时注意到某人(B)在时间戳2更改了数据。 (其中1 <2 <3),A应该覆盖B吗?还是A所做的更改应该被取消?这真的取决于应用程序逻辑。 - Eilistraee
非常感谢。现在我知道我正在正确的方向上前进! - akshay2000
缓存不依赖于本地数据库。通过周到的设计,您可以使用少量代码(没有先验知识)对整个对象图进行序列化和反序列化,而无需了解ORM类。关于AsyncLock支持的材料很棒,我之前并不知道。 - Peter Wone
显示剩余2条评论

2
我发现这篇文章因为我遇到了基本上完全相同的问题。令我惊讶的是,微软推出了自己的企业级数据库产品SQL Server,已经有几个轻量级嵌入式版本,然而似乎不能用于Windows 8/Windows Phone 8应用程序提供本地数据库。但MySQL可以! 我试图尝试写Windows Phone 8应用程序,利用我的ASP.NET/VB/.NET/SQL经验,但我总是陷入尝试学习不同的数据操作方法的泥淖中,在Web环境中可以做到的事情在W8/WP8应用程序中变得困难,最后失去兴趣。他们为什么不能使W8/WP8应用程序易于使用SQL?

如果有帮助的话,SQLite 现在已经可以在 WinRT 和 Windows Phone 上运行了。此外,Windows Phone 已经拥有强大的 SQL CE 库。 - akshay2000

0

0
  1. SQL数据库
  2. 在Windows 8和JavaScript开发中使用IndexedDB

好的!我标记了C#,那我们来谈谈SQL吧!显然,SQLite是Windows 8的一个选项。但云计算呢?假设我使用某种方式成功同步了数据库,但Windows Phone不支持它,那怎么办? - akshay2000
通过“云”,你指的是什么?Windows Azure等吗? - Senthil Kumar B
其实任何方法都可以。如果通过RoamingFolder同步整个数据库(它只有几KB),就能解决问题,我会选择这种方法。但是,我现在真的很喜欢Azure。如果您能帮助我将Azure数据库缓存到本地,那将非常有帮助。 - akshay2000

0

我知道这是一个旧问题,已经有了一个被接受的答案,但我还是要发表我的看法并回答它,因为我认为与其解决技术问题,不如使用一种不依赖于本地数据库设施的架构。

根据我的经验,很少有数据需要设备本地数据库服务。

大多数需要本地存储的用户生成数据都是非漫游(即设备特定)的用户首选项和配置(例如使用可移动存储设置)。游戏结果属于此类别。产生大量用户数据的应用程序通常在桌面上实现,并且几乎肯定具有快速可靠的本地网络连接,使得基于服务器的存储即使对于像Office文档这样的“大”数据也非常适用。

参考数据应该是基于服务器的,但您可以选择缓存它。 Windows Phone 8上的Nokia Maps就是缓存的基于服务器的数据的绝佳示例。缓存甚至可以在预期离线使用时明确地预加载。

我刚才阐述的世界观对于本地SQL Server几乎没有用处。如果您想要查询引擎,请使用LINQ。将应用程序设置和用户数据表示为对象图,并(反)序列化XML。如果您不想维护ORM类,甚至可以直接在XML上使用Linq2Xml。

任何类型的数据,如果应该在用户的所有设备上都可用,那么最好还是存储在云端。

针对Akshay的一些评论,

地图数据

地理空间数据通常以四叉树结构组织,这是出于提供随缩放级别变化的详细程度的广泛需求考虑。通过将其表示为对象图,访问和操作这些结构可以获得相当大的优势。用户不会更新它们,因此尽管这些数据在编译时可能存储在关系型数据库中,但它们肯定不是以这种方式存储或传递。

LINQ非常适用于这种情况,因为它可以直接应用于四叉树。

这些数据肯定是存储在文件中的。但我想你指的是直接的文件访问而不是通过其他进程进行间接访问。也许你心中的想法是,投入大量精力彻底解决并发和查询处理问题,并在客户端应用程序之间共享解决方案是一个好主意。但这是一种非常沉重的解决方案,而且查询处理方面已经被LINQ很好地处理了(这就是为什么我一直在提到它)。

您的XML问题

只读不需要锁定,因此通过缓存和使用Singleton模式避免文件系统锁定问题...

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];
  }
}

  1. 我已经描述了使用(XML)文件存储的问题。
  2. 本地数据库可能不是必需的,但它可以让生活变得更轻松。这也适用于缓存。
  3. 如果诺基亚地图使用文件存储而不是数据库,我会非常惊讶。
  4. 桌面电脑并不总是有网络连接。此外,这并不是限制数据只在桌面电脑上的理由。
- akshay2000

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接