How to create relationships with SQLite (Foreign key)

吃可爱长大的小学妹 提交于 2021-01-29 01:36:25

问题


I'm trying to create relationships with my tables in SQLite (I'm currently working with Xamarin.Forms), but I'm not getting the expected result, adding the Data Annotations [ForeignKey(typeof(UserLocal))] But I'm not creating the relationship in my BD, what's going on? my BD is only doing the indexed relationships, but it is not relating them to foreign keys

Browser SQLite

For the connection to my database, I created an interface which gets the route in Android and iOS, and then to manage my INSERT, UPDATE, DELETE, etc ... I do it from the DataService.CS service.

ANDROID:

[assembly: Xamarin.Forms.Dependency(typeof(PathService))]
namespace AppValora.Droid.Implementation
{
    public class PathService : IPathService
    {
        public string GetDatabasePath()
        {              
            string path = Android.OS.Environment.ExternalStorageDirectory.AbsolutePath;
            var directoryPath = Path.Combine(path, "Valora/Databases");
            if (!Directory.Exists(directoryPath))
            {
                try
                {

                    Directory.CreateDirectory(directoryPath);
                }
                catch (Exception ex)
                {

                }
            }
            return Path.Combine(directoryPath, "Valora.db3");
        }
    }
}

iOS:

[assembly: Dependency(typeof(PathService))]
namespace AppValora.iOS.Implementation
{
    public class PathService : IPathService
    {
        public string GetDatabasePath()
        {
            string docFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
            string libFolder = Path.Combine(docFolder, "..", "Library");

            if (!Directory.Exists(libFolder))
            {
                Directory.CreateDirectory(libFolder);
            }

            return Path.Combine(libFolder, "Valora.db3");
        }
    }
}

DATASERVICE.CS:

#region Servicios
private SQLiteAsyncConnection connection;
private DialogService dialogService;       
#endregion

#region Constructor
public DataService()
{
    dialogService = new DialogService();
    OpenOrCreateDB();
}
#endregion

private async Task OpenOrCreateDB()
{
    var status = await CrossPermissions.Current.CheckPermissionStatusAsync(Plugin.Permissions.Abstractions.Permission.Storage);

    if (status != Plugin.Permissions.Abstractions.PermissionStatus.Granted)
    {
        if (await CrossPermissions.Current.ShouldShowRequestPermissionRationaleAsync((Plugin.Permissions.Abstractions.Permission.Storage)))
        {
            await dialogService.ShowMessage("!ATENCIÓN!", "Valora necesita el permiso de archivos para este proceso.");
        }

        var results = await CrossPermissions.Current.RequestPermissionsAsync((Plugin.Permissions.Abstractions.Permission.Storage));
        //Best practice to always check that the key exists
        if (results.ContainsKey(Plugin.Permissions.Abstractions.Permission.Storage))
            status = results[Plugin.Permissions.Abstractions.Permission.Storage];
    }

    if (status == Plugin.Permissions.Abstractions.PermissionStatus.Granted)
    {
        //CONSULTO PATH
        var databasePath = DependencyService.Get<IPathService>().GetDatabasePath();
        //CREO LA CONEXION
        this.connection = new SQLiteAsyncConnection(databasePath);
        //CREACION DE TABLAS
        await connection.CreateTableAsync<UserLocal>().ConfigureAwait(false);
        await connection.CreateTableAsync<Companie>().ConfigureAwait(false);
    }
    else if (status != Plugin.Permissions.Abstractions.PermissionStatus.Unknown)
    {

    }    

    public async Task Insert<T>(T model)
    {
        await this.connection.InsertAsync(model);
    }
}

The DataService in addition to making the connection creates the tables in which I want to generate the relationship, The data model are the following...

USERLOCAL.CS:

public class UserLocal
{
    [PrimaryKey, AutoIncrement]
    public int Id { get; set; }

    public int IdLogin { get; set; }
    public string Token { get; set; }             
    public string Nombre { get; set; }
    public string Rut { get; set; }
    public bool Recordado { get; set; }
    public string Password { get; set; }

    [OneToMany]
    public List<Companie> Companies { get; set; }
}

COMPANIE.CS:

public class Companie
{
    [PrimaryKey, AutoIncrement]
    public int Id { get; set; }

    public int IdLogin { get; set; }
    public string Nombre { get; set; }
    public bool Principal { get; set; }
    public bool ExternalCorp { get; set; }
    public bool IsCorporate { get; set; }

    [ForeignKey(typeof(UserLocal))]
    public int IdUser { get; set; }

    [ManyToOne]
    public UserLocal UserLocal { get; set; }
}

Next, the code of how to insert the records in my tables is shown below, I think it is in this part where I am wrong, since I am not able to create the relationships

VIEWMODEL.CS:

ListaCompanie.Clear();          

// I WALK THE NUMBER OF COMPANIES THAT I WANT TO ADD
foreach (var item in loginResponse.Companies)
{
    var companie = new Companie
    {
        IdLogin = item.Id,
        Nombre = item.Name,
        ExternalCorp = item.ExternalCorp,
        IsCorporate = item.IsCorporate,
        Principal = item.Principal,
        //CLAVE FORANEA
        IdUser = loginResponse.Id,
    };

    ListaCompanie.Add(companie);

    await dataService.Insert(companie);
}

var user = new UserLocal
{
        IdLogin = loginResponse.Id,
        Nombre = loginResponse.Name,
        Recordado = Settings.Recordado,
        Rut = loginResponse.Rut,
        Token = loginResponse.Token,
        Password = GetSHA1(Settings.Password),
        Companies = ListaCompanie,
};

await dataService.Insert(user);

Why are these relationships not generated? How can I relate my tables to SQLite? what am I doing wrong? I am working with Xamarin.Forms with an MVVM architectural pattern, any help for me?


回答1:


If you are using SQLite.Net.Extensions for creating the relationships then you need to set the CascadeOperations like so:

public class UserLocal
{
    [PrimaryKey, AutoIncrement]
    public int Id { get; set; }
    public int IdLogin { get; set; }
    public string Token { get; set; }             
    public string Nombre { get; set; }
    public string Rut { get; set; }
    public bool Recordado { get; set; }
    public string Password { get; set; }

    // THIS BIT HERE 
    [OneToMany(CascadeOperations = CascadeOperation.All)]
    public List<Companie> Companies { get; set; }
}

The other thing is if you are using this library then you can insertWithChildren to create the relationship like so:

var user = new UserLocal
{
    IdLogin = loginResponse.Id,
    Nombre = loginResponse.Name,
    Recordado = Settings.Recordado,
    Rut = loginResponse.Rut,
    Token = loginResponse.Token,
    Password = GetSHA1(Settings.Password),
    Companies = ListaCompanie,
};

// I WALK THE NUMBER OF COMPANIES THAT I WANT TO ADD
foreach (var item in loginResponse.Companies)
{
    var companie = new Companie
    {
        IdLogin = item.Id,
        Nombre = item.Name,
        ExternalCorp = item.ExternalCorp,
        IsCorporate = item.IsCorporate,
        Principal = item.Principal,
        //CLAVE FORANEA
        UserLocal = user,
        // You dont need to set this as it will be assigned in InsertWithChildren
        // IdUser = loginResponse.Id,
    };

    ListaCompanie.Add(companie);

    await dataService.InsertWithChildren(companie);
}


来源:https://stackoverflow.com/questions/55573511/how-to-create-relationships-with-sqlite-foreign-key

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!