Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CASCADE verbs #148

Open
ghost opened this issue Feb 29, 2020 · 5 comments
Open

CASCADE verbs #148

ghost opened this issue Feb 29, 2020 · 5 comments

Comments

@ghost
Copy link

ghost commented Feb 29, 2020

HI, I'm exepriencing an issue with foreign key triggers.

After database creation only the ON DELETE CASCADE Keyword is present. The key ON UPDATE CASCADE is missing.
I'm using the System.ComponentModel.DataAnnotations.Schema ForeignKeyAttribute (which doesn't provide any other options).

Do you think I'm doing something wrong?

@ghost
Copy link
Author

ghost commented Feb 29, 2020

I saw in your ForeignKeyStatementBuilder.cs you have only the CascadeVerb (always on).
Why don't you add a custom ForeignKeySQLiteAttribute inheriting the ForeignKeyAttribute and adding to this the optional params OnCascade and OnUpdate verbs?

Something like:

public class ForeignKeySQLiteAttribute : ForeignKeyAttribute
{
    public bool OnUpdate { get; set; }
    public bool OnDelete { get; set; }

    public ForeignKeySQLite(string name) : base(name)
    {
        OnDelete = false;
        OnUpdate = false;
    }
}

@msallin
Copy link
Owner

msallin commented Mar 4, 2020

You don't do anything wrong. This isn't supported by the Entity Framework and therefore also not by this library.

A custom attribute could easily be implemented of course. However, I try to do this as little as possible. Can you elaborate on your use case?

@ghost
Copy link
Author

ghost commented Mar 6, 2020

Lets make a real example. This is an extract for my entities:

[Table("t_works")]
public class Work
{

[Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Column("id")]
    [Autoincrement]
    public int Id { get; private set; }

    [Column("type", TypeName = "INT")]
    [SqlDefaultValue(DefaultValue = "0")]
    [Required]
    public WorkTypes Type { get; set; }

...

public virtual ICollection<WorkEvent> Events { get; set; }

}

[Table("t_works_event")]
public class WorkEvent
{
[ForeignKey("WorkID")]
public Work WorkParent { get; set; }

    [Key]
    [Column("ref_id_work", TypeName = "INT", Order = 0)]
    public int WorkID { get; internal set; }

    [Key]
    [Column("type", TypeName = "INT", Order = 1)]
    [Required]
    public WorkEventType Type { get; set; }

    [Key]
    [Column("insert_timestamp", TypeName = "DATETIME", Order = 3)]
    public DateTime ElevationTime { get; set; }

...

}


This is an extract of the original DB I've used (created by hand):

(this table has an independent rowid)
CREATE TABLE [t_works](
[id] INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
[type] INT NOT NULL DEFAULT 0,

...

(this table has no rowid)
CREATE TABLE [t_works_event](
[ref_id_work] INTEGER NOT NULL REFERENCES t_works ON DELETE CASCADE ON UPDATE CASCADE,
[type] INT NOT NULL,
[insert_timestamp] DATETIME,

...

PRIMARY KEY([ref_id_work], [type], [insert_timestamp] ASC)) WITHOUT ROWID;
CREATE INDEX [idx_refence] ON [t_works_event]([ref_id_work] ASC);


This is the output for a created DB with your library:

CREATE TABLE "t_works" (
[id] INTEGER PRIMARY KEY AUTOINCREMENT,
[type] int NOT NULL DEFAULT (0),

...

CREATE TABLE [t_works_event](
[ref_id_work] int NOT NULL REFERENCES t_works ON DELETE CASCADE,
[type] int NOT NULL,
[insert_timestamp] datetime NOT NULL,

...

PRIMARY KEY([ref_id_work], [type], [insert_timestamp] ASC));
CREATE INDEX [IX_t_works_event_ref_id_work] ON t_works_event;


As you can see there are some differences between the original and the generated versions:

  • the rowid (a SQLite specific feature) is used everywhere instead only on the first entity type.
  • the ON DELETE CASCADE works correctly but not the ON UPDATE verb.

So if I update (change the value) of the "id" field (that is not the real id because of the rowid) in my "work" entity, the change is not propagated through all the child elements of "work_events".

My suggestion is to add two attributes: one for rowid (not strictly necessary) and one for drive delete/cascade verbs in code fisrt. The second could be a derived class from ForeignKeyAttribute.
In this way you maintain the compatibilty with the original EF framework which, i case, will get the default attribute.

Lorenzo

@NicholasRafka
Copy link

``

Sent with GitHawk

@msallin
Copy link
Owner

msallin commented Apr 25, 2020

Thanks for your explanations. I'm okay with having these custom attributes. Feel free to open a PR. Please take care that no breaking change occurs and to add corresponding unit tests & integration tests.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants