0

我在 Windows 10 通用应用程序中使用 SQLite.Net 扩展的 PCL 版本。这是我第一次使用它。它通常似乎正在工作,但它似乎是多次加载实体,而不是重用对同一对象的引用。

根据 SQLite.Net 扩展文档:

SQLite-Net Extensions 将确保任何对象只从数据库中加载一次,并将解决循环依赖和反向关系,同时保持完整的引用。这意味着具有相同标识符的同一类的任何返回对象都将是对完全相同对象的引用。

这对我来说似乎没有发生。这是我的代码:

public class Group {
    [PrimaryKey, AutoIncrement]
    public Guid Id { get; set; }

    public string GroupName { get; set; }

    public override string ToString() {
        return string.Format("Group [ID: {0}, HashCode: {1}] GroupName={2}", Id.ToString().Last(4), GetHashCode(), GroupName);
    }

    [ManyToMany(typeof(GroupMember), CascadeOperations = CascadeOperation.CascadeRead)]
    public List<Member> Members { get; set; }

    public void DebugIt() {
        Debug.WriteLine(this);
        foreach (var member in Members) Debug.WriteLine("    " + member);
    }
}

public class Member {
    [PrimaryKey, AutoIncrement]
    public Guid Id { get; set; }

    public string Name { get; set; }

    public override string ToString() {
        return string.Format("Member [ID: {0}, HashCode: {1}] Name={2}", Id.ToString().Last(4), GetHashCode(), Name);
    }

    [ManyToMany(typeof (GroupMember), CascadeOperations = CascadeOperation.CascadeRead)]
    public List<Group> Groups { get; set; }

    public void DebugIt() {
        Debug.WriteLine(this);
        foreach (var group in Groups) Debug.WriteLine("    " + group);
    }
}

public class GroupMember {
    [PrimaryKey, AutoIncrement]
    public Guid Id { get; set; }
    [ForeignKey(typeof(Group))]
    public Guid GroupID { get; set; }
    [ForeignKey(typeof(Member))]
    public Guid MemberId { get; set; }
}

public class DatabaseGroups {
    private const string FileName = "db.sqlite";
    private SQLiteConnection _db;

    public async Task<bool> LoadAsync() {
        var exists = await FileHelper.DoesFileExistAsync(FileName);
        _db = new SQLiteConnection(new SQLitePlatformWinRT(), DatabaseFullPath,
            exists ? SQLiteOpenFlags.ReadWrite : SQLiteOpenFlags.Create | SQLiteOpenFlags.ReadWrite);
        if (!exists) InitializeWithDefaults();
        return await FileHelper.DoesFileExistAsync(FileName);
    }

    private void InitializeWithDefaults() {
        _db.CreateTable<Group>();
        _db.CreateTable<Member>();
        _db.CreateTable<GroupMember>();

        var group1 = new Group {GroupName = "Group 1"};
        var group2 = new Group {GroupName = "Group 2"};
        var member1 = new Member {Name = "Bob"};
        var member2 = new Member {Name = "Jane"};

        _db.Insert(group1);
        _db.Insert(group2);
        _db.Insert(member1);
        _db.Insert(member2);

        group1.Members = new List<Member> {member1, member2};
        _db.UpdateWithChildren(group1);

        group2.Members = new List<Member> {member1, member2};
        _db.UpdateWithChildren(group2);
    }

    private static StorageFolder DatabaseFolder {
        get { return ApplicationData.Current.LocalFolder; }
    }

    private static string DatabaseFullPath {
        get { return Path.Combine(DatabaseFolder.Path, FileName); }
    }

    public void DebugIt() {
        foreach (var groupId in _db.Table<Group>().Select(g => g.Id)) {
            var group = _db.GetWithChildren<Group>(groupId);
            group.DebugIt();
        }
        foreach (var memberId in _db.Table<Member>().Select(m => m.Id)) {
            var member = _db.GetWithChildren<Member>(memberId);
            member.DebugIt();
        }
    }
}

protected override async void OnLaunched(LaunchActivatedEventArgs e) {
    _db = new DatabaseGroups();
    await _db.LoadAsync();
    _db.DebugIt();

当它运行时,我创建了一些初始数据。然后我使用 GetWithChildren 加载这些对象并对其进行调试。结果如下:

Group[ID: 4858, HashCode: 51192825] GroupName = Group 1
    Member[ID: dbfa, HashCode: 64971671] Name = Jane
    Member[ID: b047, HashCode: 30776584] Name = Bob
Group[ID: 30f0, HashCode: 53439890] GroupName = Group 2
    Member[ID: dbfa, HashCode: 36062904] Name = Jane
    Member[ID: b047, HashCode: 9089598] Name = Bob
Member[ID: b047, HashCode: 20305449] Name = Bob
    Group[ID: 30f0, HashCode: 9648315] GroupName = Group 2
    Group[ID: 4858, HashCode: 29803642] GroupName = Group 1
Member[ID: dbfa, HashCode: 36899882] Name = Jane
    Group[ID: 30f0, HashCode: 23318221] GroupName = Group 2
    Group[ID: 4858, HashCode: 60865449] GroupName = Group 1

如您所见,对象似乎加载正确,但组 1(例如)的对象引用不同(请参阅哈希码)。

我是否可能误解了 SQLite.Net Extensions 处理对象引用的方式?也许它可以在对 GetWithChildren 的一次调用中处理重用对象引用,但不能在同一个 SQLiteConnection 上的多次调用中处理?

如果是这种情况,您应该如何加载具有这些关系的更复杂的对象图?

4

1 回答 1

1

你是对的,SQLite-Net Extensions 缓存递归调用的对象以避免引用循环并处理反向关系,但它不会缓存调用之间的对象。

SQLite-Net Extensions 只是 SQLite.Net 上的一个薄层,如果整体引用对您很重要,您可以返回手动查询以进行更复杂的操作。

如果您有任何建议或拉取请求,我们随时欢迎他们;)

于 2015-06-17T08:31:32.480 回答