I am a C# Desktop developer, And I  went to android apps using Xamarin,
I used to use System.Data.SQLite.Core in my Desktop apps for SQLite.

help me make the following code compatible with sqlite-net-pcl:

private readonly SQLiteConnection _connection;

public SqLiteDatabase(string databaseName)
{
    _connection = new SQLiteConnection($"Data Source={databaseName}.db");
    _connection.Open();
    InitializeDatabase();
}
private void InitializeDatabase()
{
    const string createUsersTableSql = @"
        CREATE TABLE IF NOT EXISTS Users (
            Id TEXT PRIMARY KEY
        );
    ";

    const string createCardsTableSql = @"
        CREATE TABLE IF NOT EXISTS Cards (
            Id TEXT PRIMARY KEY,
            Units REAL,
            OwnerId INTEGER,
            Timestamp INTEGER,
            Remaining INTEGER
        );
    ";

    const string createUserCardsTableSql = @"
        CREATE TABLE IF NOT EXISTS UserCards (
            UserId TEXT,
            CardId TEXT,
            Timestamp INTEGER,
            PRIMARY KEY(UserId, CardId),
            FOREIGN KEY(UserId) REFERENCES Users(Id),
            FOREIGN KEY(CardId) REFERENCES Cards(Id)
        );
    ";

    ExecuteNonQuery(createUsersTableSql);
    ExecuteNonQuery(createCardsTableSql);
    ExecuteNonQuery(createUserCardsTableSql);
}

public async Task<User> GetOrAddUserAsync(string userId)
{
    var user = await GetUserAsync(userId);
    if (user != null) return user;

    user = new User(userId);
    await AddOrUpdateUserAsync(user);
    return user;
}
public async Task<User?> GetUserAsync(string userId)
{
    var command = _connection.CreateCommand();
    command.CommandText = @"
        SELECT Id FROM Users WHERE Id = @UserId;
    ";
    command.Parameters.AddWithValue("@UserId", userId);

    await using var reader = await command.ExecuteReaderAsync();
    if (!await reader.ReadAsync()) return null;

    var id = reader.GetString(0);
    var cards = GetUserCards(id);

    return new User(id, cards);
}
public async Task AddOrUpdateUserAsync(User user)
{
    await using var transaction = _connection.BeginTransaction();

    try
    {
        var command = _connection.CreateCommand();
        command.Transaction = transaction;
        command.CommandText = @"
            INSERT OR REPLACE INTO Users (Id)
            VALUES (@Id);
        ";
        command.Parameters.AddWithValue("@Id", user.Id);
        await command.ExecuteNonQueryAsync();

        foreach (var (key, userCard) in user.Cards)
        {
            await AddCardIfNotExistAsync(userCard.Card);
            await AssignCardToUserAsync(user.Id, key, userCard.Timestamp);
        }

        transaction.Commit();
    }
    catch (Exception)
    {
        transaction.Rollback();
        throw;
    }
}

private IEnumerable<UserCard> GetUserCards(string userId)
{
    var command = _connection.CreateCommand();
    command.CommandText = @"
        SELECT Cards.Id, Units, OwnerId, Cards.Timestamp, Remaining, UserCards.Timestamp
        FROM Cards
        JOIN UserCards ON Cards.Id = UserCards.CardId
        WHERE UserCards.UserId = @UserId;
    ";
    command.Parameters.AddWithValue("@UserId", userId);

    using var reader = command.ExecuteReader();
    while (reader.Read())
    {
        var card = new Card(
            reader.GetString(0),
            reader.GetDouble(1),
            reader.GetInt64(2),
            reader.GetInt64(3),
            reader.GetInt32(4)
        );
        yield return new UserCard(card, reader.GetInt64(5));
    }
}

public async Task AddCardIfNotExistAsync(Card card)
{
    await using var transaction = _connection.BeginTransaction();

    var command = _connection.CreateCommand();
    command.Transaction = transaction;
    command.CommandText = @"
        INSERT OR IGNORE INTO Cards (Id, Units, OwnerId, Timestamp, Remaining)
        VALUES (@Id, @Units, @OwnerId, @Timestamp, @Remaining);
    ";

    command.Parameters.AddWithValue("@Id", card.Id);
    command.Parameters.AddWithValue("@Units", card.Units);
    command.Parameters.AddWithValue("@OwnerId", card.OwnerId);
    command.Parameters.AddWithValue("@Timestamp", card.Timestamp);
    command.Parameters.AddWithValue("@Remaining", card.Remaining);
    await command.ExecuteNonQueryAsync();

    transaction.Commit();
}
public IEnumerable<Card> GetAllCards(int limit = 100)
{
    var command = _connection.CreateCommand();
    command.CommandText = @"
        SELECT Cards.Id, Units, OwnerId, Cards.Timestamp, Remaining
        FROM Cards
        LIMIT @Limit;
    ";
    command.Parameters.AddWithValue("@Limit", limit);

    using var reader = command.ExecuteReader();
    while (reader.Read())
    {
        yield return new Card(
            reader.GetString(0),
            reader.GetDouble(1),
            reader.GetInt64(2),
            reader.GetInt64(3),
            reader.GetInt32(4)
        );
    }
}
public async Task<Card?> GetCardAsync(string cardId)
{
    var command = _connection.CreateCommand();
    command.CommandText = @"
        SELECT Id, Units, OwnerId, Timestamp, Remaining FROM Cards
        WHERE Id = @CardId;
    ";

    command.Parameters.AddWithValue("@CardId", cardId);

    await using var reader = await command.ExecuteReaderAsync();
    if (await reader.ReadAsync())
    {
        return new Card(
            reader.GetString(0),
            reader.GetDouble(1),
            reader.GetInt64(2),
            reader.GetInt64(3),
            reader.GetInt32(4)
        );
    }

    return null;
}

public async Task AssignCardToUserAsync(string userId, string cardId, long timestamp)
{
    await using var transaction = _connection.BeginTransaction();

    var command = _connection.CreateCommand();
    command.Transaction = transaction;
    command.CommandText = @"
        INSERT OR REPLACE INTO UserCards (UserId, CardId, Timestamp)
        VALUES (@UserId, @CardId, @Timestamp);
    ";

    command.Parameters.AddWithValue("@UserId", userId);
    command.Parameters.AddWithValue("@CardId", cardId);
    command.Parameters.AddWithValue("@Timestamp", timestamp);
    await command.ExecuteNonQueryAsync();

    transaction.Commit();
}

private void ExecuteNonQuery(string commandText)
{
    using var command = _connection.CreateCommand();
    command.CommandText = commandText;
    command.ExecuteNonQuery();
}
public void Dispose()
{
    _connection.Dispose();
}

internal sealed class User
{
    public string Id { get; }
    public Dictionary<string, UserCard> Cards { get; }

    public User(string id)
    {
        Id = id;
        Cards = new Dictionary<string, UserCard>();
    }
    public User(string id, IEnumerable<UserCard> cards)
    {
        Id = id;
        Cards = cards.ToDictionary(c => c.Card.Id);
    }
}

internal sealed class Card
{
    public string Id { get; }
    public double Units { get; set; }
    public int Remaining { get; set; }
    public long Timestamp { get; set; }
    public long OwnerId { get; set; }
    
    public Card(string id, double units, long ownerId, long timestamp, int remaining = -1)
    {
        Id = id;
        Units = units;
        OwnerId = ownerId;
        Remaining = remaining;
        Timestamp = timestamp;
    }
}

internal sealed class UserCard
{
    public Card Card { get; set; }
    public long Timestamp { get; set; }

    public UserCard(Card card, long timestamp)
    {
        Card = card;
        Timestamp = timestamp;
    }
}